详解使用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 相关文章推荐
js几秒以后倒计时跳转示例
Dec 26 Javascript
jquery移除、绑定、触发元素事件使用示例详解
Apr 10 Javascript
JQuery中的html()、text()、val()区别示例介绍
Sep 01 Javascript
60个很实用的jQuery代码开发技巧收集
Dec 15 Javascript
微信小程序 加载 app-service.js 错误解决方法
Oct 12 Javascript
深入理解Vue router的部分高级用法
Aug 15 Javascript
JavaScrip数组去重操作实例小结
Jun 20 Javascript
JavaScript中的类型检查
Feb 03 Javascript
js实现简单扫雷
Nov 27 Javascript
JavaScript事件委托实现原理及优点进行
Aug 29 Javascript
解决Ant Design Modal内嵌Form表单initialValue值不动态更新问题
Oct 29 Javascript
微信小程序实现点击导航标签滚动定位到对应位置
Nov 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产生动态的影像图
2006/10/09 PHP
解决laravel groupBy 对查询结果进行分组出现的问题
2019/10/09 PHP
TP5框架实现的数据库备份功能示例
2020/04/05 PHP
BOOM vs RR BO5 第一场 2.14
2021/03/10 DOTA
javascript去除字符串中所有标点符号和提取纯文本的正则
2014/06/07 Javascript
使用JS画图之点、线、面
2015/01/12 Javascript
JavaScript数据类型之基本类型和引用类型的值
2015/04/01 Javascript
JS实现n秒后自动跳转的两种方法
2020/11/30 Javascript
郁闷!ionic中获取ng-model绑定的值为undefined如何解决
2016/08/27 Javascript
JS获取多维数组中相同键的值实现方法示例
2017/01/06 Javascript
javascript 删除数组元素和清空数组的简单方法
2017/02/24 Javascript
微信小程序实现点击图片旋转180度并且弹出下拉列表
2018/11/27 Javascript
如何实现一个简易版的vuex持久化工具
2019/09/11 Javascript
微信公众号H5之微信分享常见错误和问题(小结)
2019/11/14 Javascript
JS localStorage存储对象,sessionStorage存储数组对象操作示例
2020/02/15 Javascript
[04:51]TI10典藏宝瓶Ⅱ外观视频展示
2020/08/15 DOTA
Python随机生成数模块random使用实例
2015/04/13 Python
Python安装第三方库的3种方法
2015/06/21 Python
python制作爬虫并将抓取结果保存到excel中
2016/04/06 Python
Python数组定义方法
2016/04/13 Python
深入浅析python中的多进程、多线程、协程
2016/06/22 Python
python中的格式化输出用法总结
2016/07/28 Python
python抓取京东小米8手机配置信息
2018/11/13 Python
Python不同目录间进行模块调用的实现方法
2019/01/29 Python
Python中的 ansible 动态Inventory 脚本
2020/01/19 Python
Python响应对象text属性乱码解决方案
2020/03/31 Python
scrapy利用selenium爬取豆瓣阅读的全步骤
2020/09/20 Python
Python如何执行系统命令
2020/09/23 Python
CSS3田字格列表的样式编写方法
2018/11/22 HTML / CSS
美国婴儿服装购物网站:Gerber Childrenswear
2020/05/06 全球购物
营业员演讲稿
2013/12/30 职场文书
期末自我鉴定
2014/01/23 职场文书
远程培训的心得体会
2014/09/01 职场文书
2015年惩防体系建设工作总结
2015/05/22 职场文书
2015年幼儿教育工作总结
2015/07/24 职场文书
五年级作文之学校的四季
2019/12/05 职场文书