详解使用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 target与currentTarget区别说明
Aug 28 Javascript
深入理解JSON数据源格式
Jan 10 Javascript
JQuery实现动态适时改变字体颜色的方法
Mar 10 Javascript
jQuery解析XML文件同时动态增加js文件的方法
Jun 01 Javascript
angularjs学习笔记之双向数据绑定
Sep 26 Javascript
JavaScript reduce和reduceRight详解
Oct 24 Javascript
微信小程序checkbox组件使用详解
Jan 31 Javascript
js构建二叉树进行数值数组的去重与优化详解
Mar 26 Javascript
基于js中的存储键值对以及注意事项介绍
Mar 30 Javascript
jQuery实现的中英文切换功能示例
Jan 11 jQuery
JavaScript数据结构与算法之二叉树遍历算法详解【先序、中序、后序】
Feb 21 Javascript
Vue移动端项目实现使用手机预览调试操作
Jul 18 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实现可用于mysql,mssql,pg数据库操作类
2014/12/13 PHP
Nginx服务器上安装并配置PHPMyAdmin的教程
2015/08/18 PHP
PHP迭代与递归实现无限级分类
2017/08/28 PHP
Laravel5框架添加自定义辅助函数的方法
2018/08/01 PHP
基于jQuery的树控件实现代码(asp.net+json)
2010/07/11 Javascript
javascript错误的认识不用关心内存管理
2012/12/15 Javascript
Jquery中国地图热点效果-鼠标经过弹出提示层信息的简单实例
2014/02/12 Javascript
JavaScript中使用arguments获得函数传参个数实例
2014/08/27 Javascript
Javascript核心读书有感之语句
2015/02/11 Javascript
JavaScript Length 属性的总结
2015/11/02 Javascript
jQuery中$.grep() 过滤函数 数组过滤
2016/11/22 Javascript
详解Node.js项目APM监控之New Relic
2017/05/12 Javascript
vue数据双向绑定的注意点
2017/06/23 Javascript
Angular 2父子组件数据传递之@Input和@Output详解 (上)
2017/07/05 Javascript
Vue基于NUXT的SSR详解
2017/10/24 Javascript
vuejs简单验证码功能完整示例
2019/01/08 Javascript
JS原型和原型链原理与用法实例详解
2020/02/05 Javascript
Nodejs 微信小程序消息推送的实现
2021/01/20 NodeJs
Python爬虫爬验证码实现功能详解
2016/04/14 Python
python timestamp和datetime之间转换详解
2017/12/11 Python
python中字符串变二维数组的实例讲解
2018/04/03 Python
python保存文件方法小结
2018/07/27 Python
python中的for循环
2018/09/28 Python
python 将字符串完成特定的向右移动方法
2019/06/11 Python
django如何自己创建一个中间件
2019/07/24 Python
python Django里CSRF 对应策略详解
2019/08/05 Python
Python接口自动化系列之unittest结合ddt的使用教程详解
2021/02/23 Python
Python 实现劳拉游戏的实例代码(四连环、重力四子棋)
2021/03/03 Python
解决Pyinstaller打包软件失败的一个坑
2021/03/04 Python
H5新属性audio音频和video视频的控制详解(推荐)
2016/12/09 HTML / CSS
欧舒丹澳洲版:L’OCCITANE
2017/07/17 全球购物
加拿大品牌鞋包连锁店:Little Burgundy
2021/02/28 全球购物
网络维护中文求职信
2014/01/03 职场文书
幼儿园中秋节活动方案
2014/02/06 职场文书
Java各种比较对象的方式的对比总结
2021/06/20 Java/Android
JavaScript分页组件使用方法详解
2021/07/26 Javascript