详解使用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版代码高亮
Jun 26 Javascript
JavaScript DOM 学习第五章 表单简介
Feb 19 Javascript
Js如何判断客户端是PC还是手持设备简单分析
Nov 22 Javascript
cookie的secure属性详解
Apr 08 Javascript
jfinal与bootstrap的登录跳转实战演习
Sep 22 Javascript
js窗口关闭提示信息(兼容IE和firefox)
Oct 23 Javascript
浅谈Cookie的生命周期问题
Aug 02 Javascript
使用JS代码实现点击按钮下载文件
Nov 12 Javascript
Vue三层嵌套路由的示例代码
May 05 Javascript
小程序自定义日历效果
Dec 29 Javascript
详解使用React制作一个模态框
Mar 14 Javascript
ionic4+angular7+cordova上传图片功能的实例代码
Jun 19 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
PHP内核介绍及扩展开发指南―基础知识
2011/09/11 PHP
CI操作cookie的方法分析(基于helper类库)
2016/03/28 PHP
微信公众平台开发(五) 天气预报功能开发
2016/12/03 PHP
PHPStorm 2020.1 调试 Nodejs的多种方法详解
2020/09/17 NodeJs
jQuery 白痴级入门教程
2009/11/11 Javascript
javascript offsetX与layerX区别
2010/03/12 Javascript
IE与FireFox中的childNodes区别
2011/10/20 Javascript
javascript 基础篇3 类,回调函数,内置对象,事件处理
2012/03/14 Javascript
JQuery的AJAX实现文件下载的小例子
2013/05/15 Javascript
javascript中Number的方法小结
2016/11/21 Javascript
利用angular.copy取消变量的双向绑定与解析
2016/11/25 Javascript
防止重复发送 Ajax 请求
2017/02/15 Javascript
JavaScript Drum Kit 指南(纯 JS 模拟敲鼓效果)
2017/07/23 Javascript
4个顶级JavaScript高级文本编辑器
2018/10/10 Javascript
extjs图形绘制之饼图实现方法分析
2020/03/06 Javascript
echarts浮动显示单位的实现方法示例
2020/12/04 Javascript
[01:23:59]2018DOTA2亚洲邀请赛 4.1 小组赛 B组 VP vs Secret
2018/04/03 DOTA
用Python的urllib库提交WEB表单
2009/02/24 Python
Python对两个有序列表进行合并和排序的例子
2014/06/13 Python
解决pyqt中ui编译成窗体.py中文乱码的问题
2016/12/23 Python
python下读取公私钥做加解密实例详解
2017/03/29 Python
对python GUI实现完美进度条的示例详解
2018/12/13 Python
Django之Mode的外键自关联和引用未定义的Model方法
2018/12/15 Python
python实现静态web服务器
2019/09/03 Python
python针对mysql数据库的连接、查询、更新、删除操作示例
2019/09/11 Python
基于K.image_data_format() == 'channels_first' 的理解
2020/06/29 Python
世界上最大的各式箱包网络零售店:eBag
2016/07/21 全球购物
客服专员岗位职责范本
2013/11/29 职场文书
优秀部门获奖感言
2014/02/14 职场文书
个人工作主要事迹
2014/05/08 职场文书
趣味运动会开幕词
2015/01/28 职场文书
倡议书范文大全
2015/04/28 职场文书
职位证明模板
2015/06/23 职场文书
机关单位2016年法制宣传日活动总结
2016/04/01 职场文书
python中pd.cut()与pd.qcut()的对比及示例
2022/06/16 Python
MySQL约束(创建表时的各种条件说明)
2022/06/21 MySQL