详解使用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 相关文章推荐
自动检查并替换文本框内的字符
Jun 30 Javascript
JS解密入门 最终变量劫持
Jun 25 Javascript
FF(火狐)浏览器无法执行window.close()解决方案
Nov 13 Javascript
基于jquery实现的自动补全功能
Mar 12 Javascript
jquery利用拖拽方式在图片上添加热链接
Nov 24 Javascript
canvas实现绘制吃豆鱼效果
Jan 12 Javascript
vue input 输入校验字母数字组合且长度小于30的实现代码
May 16 Javascript
基于js Canvas实现二次贝塞尔曲线
Dec 25 Javascript
JS实现的图片选择顺序切换和循环切换功能示例【测试可用】
Dec 28 Javascript
JS块级作用域和私有变量实例分析
May 11 Javascript
ES6 Proxy实现Vue的变化检测问题
Jun 11 Javascript
解决vue项目中遇到 Cannot find module ‘chalk‘ 报错的问题
Nov 05 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
一个好用的分页函数
2006/11/16 PHP
php实现文件下载(支持中文文名)
2013/12/04 PHP
PHP操作FTP类 (上传、下载、移动、创建等)
2016/03/31 PHP
php生成mysql的数据字典
2016/07/07 PHP
js String对象中常用方法小结(字符串操作)
2012/01/27 Javascript
javascript面向对象入门基础详细介绍
2012/09/05 Javascript
5秒后跳转到另一个页面的js代码
2013/10/12 Javascript
鼠标滚轮改变图片大小的示例代码
2013/11/20 Javascript
indexOf 和 lastIndexOf 使用示例介绍
2014/09/02 Javascript
JS中的Replace方法使用经验分享
2015/05/20 Javascript
jQuery实现带水平滑杆的焦点图动画插件
2016/03/08 Javascript
Javascript获取随机数的实现方法
2016/06/22 Javascript
基于JS如何实现给字符加千分符(65,541,694,158)
2016/08/03 Javascript
如何写好你的JavaScript【推荐】
2017/03/02 Javascript
Angular中自定义Debounce Click指令防止重复点击
2017/07/26 Javascript
微信小程序自定义toast弹窗效果的实现代码
2018/11/15 Javascript
解决使用layui对select append元素无效或者未及时更新的问题
2019/09/18 Javascript
[38:39]KG vs Mineski 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
[38:32]完美世界DOTA2联赛循环赛 Forest vs DM 第二场 11.06
2020/11/06 DOTA
跟老齐学Python之让人欢喜让人忧的迭代
2014/10/02 Python
浅析AST抽象语法树及Python代码实现
2016/06/06 Python
python3 pillow生成简单验证码图片的示例
2017/09/19 Python
python开启摄像头以及深度学习实现目标检测方法
2018/08/03 Python
Python并发之多进程的方法实例代码
2018/08/15 Python
python实现nao机器人身体躯干和腿部动作操作
2019/04/29 Python
Numpy数组array和矩阵matrix转换方法
2019/08/05 Python
python怎么调用自己的函数
2020/07/01 Python
翻新二手苹果产品的网络领导者:Mac of all Trades
2017/12/19 全球购物
大学生学习党课思想汇报
2014/01/03 职场文书
自荐信如何制作?
2014/02/21 职场文书
融资合作协议书范本
2014/10/17 职场文书
党员民主评议自我评价
2014/10/20 职场文书
个人作风建设心得体会
2014/10/22 职场文书
教师节作文之小学四年级
2019/09/03 职场文书
导游词之珠海轮廓
2019/10/25 职场文书
MySQL 十大常用字符串函数详解
2021/06/30 MySQL