详解使用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 相关文章推荐
网上应用的一个不错common.js脚本
Aug 08 Javascript
jquery实现checkbox 全选/全不选的通用写法
Feb 22 Javascript
Js实现滚动变色的文字效果
Jun 16 Javascript
JavaScript中输出标签的方法
Aug 27 Javascript
jquery单行文字向上滚动效果的实现代码
Sep 05 Javascript
javascript感应鼠标图片透明度显示的方法
Feb 24 Javascript
JavaScript常用标签和方法总结
Sep 01 Javascript
javascript解析ajax返回的xml和json格式数据实例详解
Jan 05 Javascript
完美实现js焦点轮播效果(一)
Mar 07 Javascript
利用vueJs实现图片轮播实例代码
Jun 03 Javascript
vue教程之toast弹框全局调用示例详解
Aug 24 Javascript
vue-cli3配置favicon.ico和title的流程
Oct 27 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 小心urldecode引发的SQL注入漏洞
2011/10/27 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(四)
2014/06/23 PHP
PHP的中使用非缓冲模式查询数据库的方法
2017/02/05 PHP
实例讲解PHP表单处理
2019/02/15 PHP
php实现微信公众号创建自定义菜单功能的实例代码
2019/06/11 PHP
让innerHTML的脚本也可以运行起来
2006/07/01 Javascript
学习ExtJS TextField常用方法
2009/10/07 Javascript
jQuery表单域选择器用法分析
2015/02/10 Javascript
JavaScript随机生成信用卡卡号的方法
2015/04/07 Javascript
jQuery实现的数值范围range2dslider选取插件特效多款代码分享
2015/08/27 Javascript
jQuery简单实现上下,左右滑动的方法
2016/06/01 Javascript
Vue.js 表单校验插件
2016/08/14 Javascript
BootStrap 实现各种样式的进度条效果
2016/12/07 Javascript
WebView启动支付宝客户端支付失败的问题小结
2017/01/11 Javascript
javascript checkbox/radio onchange不能兼容ie8处理办法
2017/06/13 Javascript
Node.js实现mysql连接池使用事务自动回收连接的方法示例
2018/02/03 Javascript
JavaScript实现单图片上传并预览功能
2019/09/30 Javascript
python基础教程之简单入门说明(变量和控制语言使用方法)
2014/03/25 Python
《Python之禅》中对于Python编程过程中的一些建议
2015/04/03 Python
Python在Console下显示文本进度条的方法
2016/02/14 Python
解决python读取几千万行的大表内存问题
2018/06/26 Python
Python3日期与时间戳转换的几种方法详解
2019/06/04 Python
解决TensorFlow模型恢复报错的问题
2020/02/06 Python
使用Python防止SQL注入攻击的实现示例
2020/05/21 Python
HTML5印章绘制电子签章图片(中文英文椭圆章、中文英文椭圆印章)
2019/06/03 HTML / CSS
美国购买肉、鸭、家禽、鹅肝和熟食网站:D’Artagnan
2018/11/13 全球购物
餐厅楼面主管岗位职责范本
2014/02/16 职场文书
宿舍保安职务说明书
2014/02/25 职场文书
法院先进个人事迹材料
2014/05/04 职场文书
毕业生党员个人总结
2015/02/14 职场文书
驾驶员安全责任协议书
2016/03/22 职场文书
闭幕词的写作格式与范文!
2019/06/24 职场文书
2019年行政人事个人工作总结范本!
2019/07/19 职场文书
PHP中->和=>的意思
2021/03/31 PHP
Flutter Navigator 实现路由传递参数
2022/04/22 Java/Android
Win11怎么添加用户?Win11添加用户账户的方法
2022/07/15 数码科技