详解使用webpack构建多页面应用


Posted in Javascript onDecember 21, 2017

关于webpack的配置和使用,网上已经有许多文章了,大多是在讲单页应用,当我们需要打包多个html时,事情就变得麻烦起来。怎么在webpack-dev-server里使用路由?怎么打包多个html和js chunk并自动更新md5?本文讲的就是如何解决这些问题。

这里假设你对Webpack已经有最基础的了解

需求

来看下我们的需求:

  1. 使用webpack-dev-server做开发时的服务器
  2. 在webpack-dev-server里使用路由,访问/a时候显示a.html,/b显示b.html
  3. 打包成多个html,给其中引用到资源加md5戳

主要目录结构

├── src            
│  └── views         # 每一个文件夹对应一个页面
│    └── a         
│      └── index.js
│    └── b         
│      └── index.js
├── output          # 打包输出的目录
|  └── ...
└── template.html       # 将根据这个模版,生成各个页面的html
└── webpack.config.js
└── dev-server.js       # webpack-dev-server + express

只列出了主要的目录,这里我们根据一个template.html来生成多个页面的html,他们之间只有引用的资源路径不同。当然,你也可以每个页面单独使用一个html模版。

Webpack 配置

这里主要解决两个小问题。

1. 打包多个页面的js文件

读取src/views下的目录,约定每一个目录当成一个页面,打包成一个js chunk。

2. 打包多个html

循环生成多个HtmlWebpackPlugin插件,把每一个插件的chunks各自指向上面打包的js chunk。

// webpack.config.js
var glob = require('glob');

var webpackConfig = {
  /* 一些webpack基础配置 */  
};

// 获取指定路径下的入口文件
function getEntries(globPath) {
   var files = glob.sync(globPath),
    entries = {};

   files.forEach(function(filepath) {
     // 取倒数第二层(view下面的文件夹)做包名
     var split = filepath.split('/');
     var name = split[split.length - 2];

     entries[name] = './' + filepath;
   });

   return entries;
}
    
var entries = getEntries('src/view/**/index.js');

Object.keys(entries).forEach(function(name) {
  // 每个页面生成一个entry,如果需要HotUpdate,在这里修改entry
  webpackConfig.entry[name] = entries[name];
  
  // 每个页面生成一个html
  var plugin = new HtmlWebpackPlugin({
    // 生成出来的html文件名
    filename: name + '.html',
    // 每个html的模版,这里多个页面使用同一个模版
    template: './template.html',
    // 自动将引用插入html
    inject: true,
    // 每个html引用的js模块,也可以在这里加上vendor等公用模块
    chunks: [name]
  });
  webpackConfig.plugins.push(plugin);
})

路由配置

在多页应用下,我们希望访问的是localhost:8080/a,而不是localhost:8080/a.html。

由于webpack-dev-server只是将文件打包在内存里,所以你没法在express里直接sendfile('output/views/a.html'),因为这个文件实际上还不存在。还好webpack提供了一个outputFileStream,用来输出其内存里的文件,我们可以利用它来做路由。

注意,为了自定义路由,你可能需要引进express或koa之类的库,然后将webpack-dev-server作为中间件处理。

// dev-server.js
var express = require('express')
var webpack = require('webpack')
var webpackConfig = require('./webpack.config')

var app = express();

// webpack编译器
var compiler = webpack(webpackConfig);

// webpack-dev-server中间件
var devMiddleware = require('webpack-dev-middleware')(compiler, {
  publicPath: webpackConfig.output.publicPath,
  stats: {
    colors: true,
    chunks: false
  }
});

app.use(devMiddleware)

// 路由
app.get('/:viewname?', function(req, res, next) {
  
  var viewname = req.params.viewname 
    ? req.params.viewname + '.html' 
    : 'index.html';
    
  var filepath = path.join(compiler.outputPath, viewname);
  
  // 使用webpack提供的outputFileSystem
  compiler.outputFileSystem.readFile(filepath, function(err, result) {
    if (err) {
      // something error
      return next(err);
    }
    res.set('content-type', 'text/html');
    res.send(result);
    res.end();
  });
});

module.exports = app.listen(8080, function(err) {
  if (err) {
    // do something
    return;
  }
  
  console.log('Listening at http://localhost:' + port + '\n')
})

最后,在package.json里定义下启动命令:

// package.json
{
  scripts: {
    "dev": "node ./dev-server.js"  
  }
}

运行 npm run dev,然后在浏览器访问localhost:8080/各个页面,你应该可以看到想要的结果。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript 自动完成脚本整理(33个)
Oct 20 Javascript
C#中TrimStart,TrimEnd,Trim在javascript上的实现
Jan 17 Javascript
JQuery 图片滚动轮播示例代码
Mar 24 Javascript
JavaScript实现找质数代码分享
Mar 24 Javascript
JS出现失效的情况总结
Jan 20 Javascript
vue 全选与反选的实现方法(无Bug 新手看过来)
Feb 09 Javascript
浅析JS中什么是自定义react数据验证组件
Oct 19 Javascript
layer.open提交子页面的form和layedit文本编辑内容的方法
Sep 27 Javascript
vuex state中的数组变化监听实例
Nov 06 Javascript
vue+animation实现翻页动画
Jun 29 Javascript
Nuxt.js nuxt-link与router-link的区别说明
Nov 06 Javascript
js实现简易点击切换显示或隐藏
Nov 29 Javascript
使用ajax的post同步执行(实现方法)
Dec 21 #Javascript
jQuery Validate插件ajax方式验证输入值的实例
Dec 21 #jQuery
原生js+cookie实现购物车功能的方法分析
Dec 21 #Javascript
JS实现去除数组中重复json的方法示例
Dec 21 #Javascript
解析vue中的$mount
Dec 21 #Javascript
vue中使用refs定位dom出现undefined的解决方法
Dec 21 #Javascript
js中bool值的转换及“&&”、“||”、 “!!”详解
Dec 21 #Javascript
You might like
10个实用的PHP代码片段
2011/09/02 PHP
php中替换字符串中的空格为逗号','的方法
2014/06/09 PHP
PHP计算加权平均数的方法
2015/07/16 PHP
PHP实现自动识别原编码并对字符串进行编码转换的方法
2016/07/13 PHP
静态页面的值传递(三部曲)
2006/09/25 Javascript
用javascript获得地址栏参数的两种方法
2006/11/08 Javascript
js 获取浏览器高度和宽度值(多浏览器)
2009/09/02 Javascript
你必须知道的Javascript知识点之"this指针"的应用
2013/04/23 Javascript
jquery移动节点实例
2015/01/14 Javascript
JS+CSS实现实用的单击输入框弹出选择框的方法
2015/02/28 Javascript
理解JS事件循环
2016/01/07 Javascript
详谈JS中实现种子随机数及作用
2016/07/19 Javascript
jQuery在ie6下无法设置select选中的解决方法详解
2016/09/20 Javascript
js 转义字符及URI编码详解
2017/02/28 Javascript
JavaScript实现简单的四则运算计算器完整实例
2017/04/28 Javascript
mpvue 单文件页面配置详解
2018/12/02 Javascript
three.js搭建室内场景教程
2018/12/30 Javascript
JavaScript之解构赋值的理解
2019/01/30 Javascript
ES6的异步操作之promise用法和async函数的具体使用
2019/12/06 Javascript
JS实现transform实现扇子效果
2020/01/17 Javascript
vue组件创建的三种方式小结
2020/02/03 Javascript
[04:29]DOTA2亚洲邀请赛小组赛第一日 TOP10精彩集锦
2015/02/01 DOTA
[02:37]2018DOTA2亚洲邀请赛赛前采访 VP.no[o]ne心中最强SOLO是谁
2018/04/04 DOTA
跟老齐学Python之私有函数和专有方法
2014/10/24 Python
python中查看变量内存地址的方法
2015/05/05 Python
python散点图实例之随机漫步
2018/08/27 Python
Pycharm常用快捷键总结及配置方法
2020/11/14 Python
前端面试必备之CSS3的新特性
2017/09/05 HTML / CSS
林清轩官方网站:山茶花润肤油开创者
2016/10/26 全球购物
美国婚礼装饰和活动用品批发供应商:Event Decor Direct
2018/10/12 全球购物
大学生物业管理求职信
2013/10/24 职场文书
幼儿园家长会邀请函
2014/01/15 职场文书
向领导表决心的话
2014/03/11 职场文书
大学生求职信怎么写
2015/03/19 职场文书
借条如何写
2015/05/26 职场文书
Python读取文件夹下的所有文件实例代码
2021/04/02 Python