详解使用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 相关文章推荐
JQuery中对Select的option项的添加、删除、取值
Aug 25 Javascript
JS实现固定在右下角可展开收缩DIV层的方法
Feb 13 Javascript
JavaScript实现计算字符串中出现次数最多的字符和出现的次数
Mar 12 Javascript
基于Javascript实现倒计时功能
Feb 22 Javascript
jQuery中text() val()和html()的区别实例详解
Jun 28 Javascript
强大的 Angular 表单验证功能详细介绍
May 23 Javascript
vue事件修饰符和按键修饰符用法总结
Jul 25 Javascript
使用原生js封装的ajax实例(兼容jsonp)
Oct 12 Javascript
Layui 设置select下拉框自动选中某项的方法
Aug 14 Javascript
vue使用axios上传文件(FormData)的方法
Apr 14 Javascript
JS实现的对象去重功能示例
Jun 04 Javascript
一起来看看Vue的核心原理剖析
Mar 24 Vue.js
使用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截取字符串并保留完整xml标签的函数代码
2013/02/06 PHP
深入解析PHP的Laravel框架中的event事件操作
2016/03/21 PHP
jquery连缀语法如何实现
2012/11/29 Javascript
网页整体变灰白色(兼容各浏览器)实例
2013/04/21 Javascript
jQuery bxCarousel实现图片滚动切换效果示例代码
2013/05/15 Javascript
制作jquery遮罩层效果导航菜单代码分享
2013/12/25 Javascript
Bootstrap实现响应式导航栏效果
2015/12/28 Javascript
JavaScript中自带的 reduce()方法使用示例详解
2016/08/10 Javascript
AngularJS通过$location获取及改变当前页面的URL
2016/09/23 Javascript
js前端解决跨域问题的8种方案(最新最全)
2016/11/18 Javascript
JavaScript实现经纬度转换成地址功能
2017/03/28 Javascript
jQuery实现腾讯信用界面(自制刻度尺)样式
2017/08/15 jQuery
详解vue 模拟后台数据(加载本地json文件)调试
2017/08/25 Javascript
详解Vue-cli代理解决跨域问题
2017/09/27 Javascript
two.js之实现动画效果示例
2017/11/06 Javascript
js与jQuery实现的用户注册协议倒计时功能实例【三种方法】
2017/11/09 jQuery
详解Vue中localstorage和sessionstorage的使用
2017/12/22 Javascript
element-ui 时间选择器限制范围的实现(随动)
2019/01/09 Javascript
在layer弹层layer.prompt中,修改placeholder的实现方法
2019/09/27 Javascript
Python列表append和+的区别浅析
2015/02/02 Python
详解Python当中的字符串和编码
2015/04/25 Python
Python的Django框架中settings文件的部署建议
2015/05/30 Python
浅谈python 读excel数值为浮点型的问题
2018/12/25 Python
Python 3.3实现计算两个日期间隔秒数/天数的方法示例
2019/01/07 Python
一行python实现树形结构的方法
2019/08/09 Python
如何基于python把文字图片写入word文档
2020/07/31 Python
CSS3伪类选择器:nth-child()
2009/04/02 HTML / CSS
国外平面设计第一市场:99designs
2016/10/25 全球购物
Clearly澳大利亚:购买眼镜、太阳镜和隐形眼镜
2018/04/26 全球购物
PHP高级工程师面试问题推荐
2013/01/18 面试题
Java中实现多态的机制是什么?
2014/12/07 面试题
Internet体系结构
2014/12/21 面试题
大学生学业生涯规划
2014/01/05 职场文书
倡议书格式及范文
2015/04/29 职场文书
Redis分布式锁Redlock的实现
2021/08/07 Redis
JavaScript实现九宫格拖拽效果
2022/06/28 Javascript