详解使用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 实现的点击复制代码
Mar 24 Javascript
JQUBar 基于JQUERY的柱状图插件
Nov 23 Javascript
js substr、substring和slice使用说明小记
Sep 15 Javascript
JavaScript数组常用操作技巧汇总
Nov 17 Javascript
jQuery实现鼠标滑过点击事件音效试听
Aug 31 Javascript
Jquery 垂直多级手风琴菜单附源码下载
Nov 17 Javascript
纯js实现图片匀速淡入淡出效果
Aug 22 Javascript
基于vue开发的在线付费课程应用过程
Jan 25 Javascript
JS实现快递单打印功能【推荐】
Jun 21 Javascript
JS实现可视化音频效果的实例代码
Jan 16 Javascript
解决vue项目中某一页面不想引用公共组件app.vue的问题
Aug 14 Javascript
在vue项目中promise解决回调地狱和并发请求的问题
Nov 09 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
用PHPdig打造属于你自己的Google[图文教程]
2007/02/14 PHP
PHP中的string类型使用说明
2010/07/27 PHP
Php中用PDO查询Mysql来避免SQL注入风险的方法
2013/04/25 PHP
php实现贪吃蛇小游戏
2016/07/26 PHP
thinkphp3.2.0 setInc方法 源码全面解析
2018/01/29 PHP
PHP设计模式之PHP迭代器模式讲解
2019/03/22 PHP
javascript 字符串连接的性能问题(多浏览器)
2008/11/18 Javascript
jQuery Pagination Ajax分页插件(分页切换时无刷新与延迟)中文翻译版
2013/01/11 Javascript
JS特殊函数(Function()构造函数、函数直接量)区别介绍
2013/05/19 Javascript
jQuery选择器querySelector的使用指南
2015/01/23 Javascript
JavaScript学习笔记(三):JavaScript也有入口Main函数
2015/09/12 Javascript
JavaScript中闭包的写法和作用详解
2016/06/29 Javascript
AngularJS入门教程中SQL实例详解
2016/07/27 Javascript
Angular 页面跳转时传参问题
2016/08/01 Javascript
JavaScript设置名字输入不合法的实现方法
2017/05/23 Javascript
Vue.js添加组件操作示例
2018/06/13 Javascript
Nodejs调用Dll模块的方法
2018/09/17 NodeJs
ES6 Map结构的应用实例分析
2019/06/26 Javascript
layer提示框添加多个按钮选择的实例
2019/09/12 Javascript
vue3自定义dialog、modal组件的方法
2021/01/04 Vue.js
[02:58]魔廷新尊——痛苦女王至宝语音台词节选
2020/06/14 DOTA
深入解析Python编程中JSON模块的使用
2015/10/15 Python
Python使用os模块和fileinput模块来操作文件目录
2016/01/19 Python
Python解惑之整数比较详解
2017/04/24 Python
python读取csv和txt数据转换成向量的实例
2019/02/12 Python
python交易记录整合交易类详解
2019/07/03 Python
Python异常处理例题整理
2019/07/07 Python
django实现模型字段动态choice的操作
2020/04/01 Python
浅析python 字典嵌套
2020/09/29 Python
逻辑链路控制协议
2016/10/01 面试题
简述Linux文件系统通过i节点把文件的逻辑结构和物理结构转换的工作过程
2016/01/06 面试题
高三地理教学反思
2014/01/11 职场文书
公司租房协议书范本
2014/10/08 职场文书
教师党员学习十八届四中全会思想汇报
2014/11/03 职场文书
2015大学生党员自我评价范文
2015/03/03 职场文书
小学语文教师竞聘演讲稿范文
2019/08/09 职场文书