传统的多页面网站(MPA)能否用webpack打包?
对于多页面网站, 我们最多的是用Grunt或Gulp来打包, 因为这种简单的页面对模块化编程的需求不高. 但如果你喜欢上使用import
来引入库, 那么我们仍然可以使用webpack来打包.
MPA意味着并没不是一个单一的html入口和js入口, 而是每个页面对应一个html和多个js. 那么我们可以把项目结构设计为:
├── dist
├── package.json
├── node_modules
├── src
│ ├── components
│ ├── libs
| ├── favicon.png
| ├── vendor.js 所有页面公用的第三方库
│ └── pages 页面放这里
| ├── foo 编译后生成 http://localhost:8100/foo.html
| | ├── index.html
| | ├── index.js
| | ├── style.css
| | └── pic.png
| └── bar http://localhost:8100/bar.html
| ├── index.html
| ├── index.js
| ├── style.css
| └── baz http://localhost:8100/bar/baz.html
| ├── index.html
| ├── index.js
| └── style.css
└── webpack.config.js
这里每个页面的index.html
是个完整的从<!DOCTYPE html>
开头到</html>
结束的页面, 这些文件都要用html-webpack-plugin
处理. index.js
是每个页面的业务逻辑, 全部作为入口js配置到entry
中. 页面公用的第三方库仍然打包进vendor.js
. 这里我们需要用glob
库来把这些文件都筛选出来批量操作.
npm install glob --save-dev
webpack.config.js
修改的地方:
// ...
const glob = require('glob')
module.exports = (options = {}) => {
// ...
const entries = glob.sync('./src/**/index.js')
const entryJsList = {}
const entryHtmlList = []
for (const path of entries) {
const chunkName = path.slice('./src/pages/'.length, -'/index.js'.length)
entryJsList[chunkName] = path
entryHtmlList.push(new HtmlWebpackPlugin({
template: path.replace('index.js', 'index.html'),
filename: chunkName + '.html',
chunks: ['manifest', 'vendor', chunkName]
}))
}
return {
entry: Object.assign({
vendor: './src/vendor'
}, entryJsList),
// ...
plugins: [
...entryHtmlList,
// ...
]
}
}
代码在examples/mpa目录.
其他问题
为什么不使用webpack.config.babel.js
部分同学可能知道webpack可以读取webpack.config.babel.js, 它会先调用babel将文件编译后再执行. 但这里有两个坑:
- 由于我们的package.json中的babel配置指定了
modules: false
, 所以babel并不会转码import
, 这导致编译后的webpack配置文件仍然无法在node.js中执行, 解决方案是package.json不指定modules: false
, 而在babel-loader中的options中配置babel. 这样webpack.config.babel.js会使用package.json的babel配置编译, 而webpack编译的js会使用babel-loader指定的配置编译.
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
['env', {
loose: true,
modules: false
}],
'stage-2'
]
}
},
'eslint-loader'
]
}
- postcss的配置不支持先用babel转码, 这导致了我们的配置文件格式的不统一.
综上, 还是只在src目录中的文件使用ES6模块规范会比较方便一点.
总结
通过这篇文章, 我想大家应该学会了webpack的正确打开姿势. 虽然我没有提及如何用webpack来编译React和vue.js, 但大家可以想到, 无非是安装一些loader和plugin来处理jsx和vue格式的文件, 那时难度就不在于webpack了, 而是代码架构组织的问题了. 具体的大家自己去摸索一下. 以后有时间我会把脚手架整理一下放到github上, 供大家参考.