详解使用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 相关文章推荐
让Firefox支持event对象实现代码
Nov 07 Javascript
用JSON做数据传输格式中的一些问题总结
Dec 21 Javascript
jquery的冒泡事件的阻止与允许(三种实现方法)
Feb 01 Javascript
Javascript中的for in循环和hasOwnProperty结合使用
Jun 05 Javascript
jquery实现微博文字输入框 输入时显示输入字数 效果实现
Jul 12 Javascript
jquery实现图片预加载
Dec 25 Javascript
高性能JavaScript循环语句和条件语句
Jan 20 Javascript
超级简易的JS计算器实例讲解(实现加减乘除)
Aug 08 Javascript
解决jquery appaend元素中id绑定事件失效的问题
Sep 12 jQuery
JS实现table表格内针对某列内容进行即时搜索筛选功能
May 11 Javascript
详解vue-cli项目开发/生产环境代理实现跨域请求
Jul 23 Javascript
如何在vue 中引入使用jquery
Nov 10 jQuery
使用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
DOTA2 无惧惊涛骇浪 昆卡大型水友攻略
2020/04/20 DOTA
PHP新手上路(四)
2006/10/09 PHP
PHP使用DOMDocument类生成HTML实例(包含常见标签元素)
2014/06/25 PHP
PHP操作mysql数据库分表的方法
2016/06/09 PHP
jQuery autocomplete插件修改
2009/04/17 Javascript
script标签的 charset 属性使用说明
2010/12/04 Javascript
解决javascript:window.close()在chrome,Firefox下失效的问题
2013/05/07 Javascript
js/jquery去掉空格,回车,换行示例代码
2013/11/05 Javascript
jquery中的查找parents与closest方法之间的区别
2013/12/02 Javascript
BOM系列第三篇之定时器应用(时钟、倒计时、秒表和闹钟)
2016/08/17 Javascript
Chrome不支持showModalDialog模态对话框和无法返回returnValue问题的解决方法
2016/10/30 Javascript
浅谈jquery选择器 :first与:first-child的区别
2016/11/20 Javascript
简单实现jQuery多选框功能
2017/01/09 Javascript
ES6数组的扩展详解
2017/04/25 Javascript
JS实现图片手风琴效果
2020/04/17 Javascript
Vue-cli创建项目从单页面到多页面的方法
2017/09/20 Javascript
详解如何使用babel进行es6文件的编译
2018/05/29 Javascript
Vue + Elementui实现多标签页共存的方法
2019/06/12 Javascript
phpsir 开发 一个检测百度关键字网站排名的python 程序
2009/09/17 Python
跟老齐学Python之重回函数
2014/10/10 Python
讲解Python中if语句的嵌套用法
2015/05/14 Python
python 调用HBase的简单实例
2016/12/18 Python
Django 如何获取前端发送的头文件详解(推荐)
2017/08/15 Python
python3判断url链接是否为404的方法
2018/08/10 Python
python多进程下实现日志记录按时间分割
2019/07/22 Python
在python image 中安装中文字体的实现方法
2019/08/22 Python
pip install python 快速安装模块的教程图解
2019/10/08 Python
python使用Matplotlib改变坐标轴的默认位置
2019/10/18 Python
numpy按列连接两个维数不同的数组方式
2019/12/06 Python
Python实现图片指定位置加图片水印(附Pyinstaller打包exe)
2021/03/04 Python
咖啡书吧创业计划书
2014/01/13 职场文书
教育专业毕业生推荐信
2014/07/10 职场文书
党员学习中共十八大思想报告
2014/09/12 职场文书
基层党员四风问题自我剖析材料
2014/09/29 职场文书
介绍信怎么写
2015/01/30 职场文书
2015年学校教研室主任工作总结
2015/07/20 职场文书