使用 webpack 已经将近一年了,期间用它构建过4、5个项目,踩过一些坑,现在用自己的理解记录下来。
我现在教你如何一步一步搭建 webpack 开发的多页面项目。
git clone https://github.com/fe-config/generate-pages-tutorial
这里使用的是 webpack 1.x
注意每一步的 webpack.config.js
和 pageage.json
一、基本 JavaScript 模块的处理
cd 1_multi_pages
npm install
npm run build
查看 webpack.config.js
可以其实就是配置多个 entry 而已,可以看到 dist 下生成编译好的文件:
|--- dist
|--- page1
|--- main.js
|--- page2
|--- main.js
这里的目录层级和 entry 中的模块名(page1/main、page2/main
)对应。
打开 page1.html 和 page2.html 就可以看到我们的js模块生效了。现在进入下一步!
二、CSS 模块的处理
通过上一步,我们已经解决了 JavaScript 模块的问题,而页面中还有 CSS 。webpack 默认是只处理 JavaScript 的,所以我们要引入 css-loader
和 style-loader
来处理 CSS。
cd 2_css
npm install
npm run build
CSS
{
test: /\.css$/,
loaders: ['style', 'css']
}
loader 是专门处理某些模块的处理器。webpack 只能处理 js ,为了能够处理 CSS ,就需要 css-loader;而为了能够在页面中插入 CSS ,还需要 style-loader
。
打开 page1.html
就可以看到 css 生效了。
less
{
test: /\.less$/,
loaders: ['style', 'css', 'less']
}
如果使用的是 less ,就需要安装 less 和 less-loader
。
打开 page2.html 就可以看到 less 生效了。
sass
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass']
}
如果使用的是 sass ,就需要安装 node-sass
和 sass-loader
。
打开 page3.html 就可以看到 less 生效了。
postcss
module: {
loaders: [
{
test: /\.css$/,
include: ROOT + '/src/page4',
loaders: ['style', 'css', 'postcss']
}
]
},
postcss: function() {
return [autoprefixer]
}
如果使用的是 sass ,就需要安装 post-loader
,这里是以 autoprefixer
为例。
打开 page4.html 就可以看到 less 生效了。
生成 CSS 文件
以上方法都是用 JS 生成 CSS,但是实际上,我们需要的是 CSS 文件,可以使用 extract-text-webpack-plugin
来解决。
打开 page5.html 可以看到效果
三、reload
上面2节我们已经掌握 JS 模块和 CSS 模块的处理,并且能够让 CSS 独立生成文件了,现在我们觉得每次修改代码然后 build 再刷新浏览器这个过程实在太慢了,而且也没必要每修改一行代码,就生成新文件,这是构建速度慢的主要原因。
webpack-dev-server
是 webpack 自带的一个开发服务器,支持热替换、代理等等功能。
cd 3_reload
npm install
npm run dev
打开 0.0.0.0:8888/page1.html ,你就可以看到页面了。而且无论你修改 main.js、 style.css或 tpl/page1.html 都会让浏览器自动刷新。
这里使用了:
- html-webpack-plugin: 在页面中自动注入 js 和 css
- html-webpack-harddisk-plugin: 每次修改 pages/tpl 内文件时,会自动在 pages/html 内生成对应的文件
-
raw-loader: 可以 require html 文件,做到每修改一次 tpl 文件,浏览器自动刷新一次页面 还有一点值得注意,因为 reload 功能是开发时才需要的,所以我们在 build 的时候要把这部分剔除,cross-env 和 DefinePlugin 的配合可以做到这点。
- cross-env 能够不分系统地在全局注入变量,下面这条命令就是将 DEV 注入 ENV 环境变量
cross-env ENV=DEV webpack-dev-server --inline --hot --quiet --progress --content-base pages/html --host 0.0.0.0 --port 8888
- DefinePlugin 将 process.env.ENV 这个环境变量注入 ENV 中
new webpack.DefinePlugin({ 'ENV': JSON.stringify(process.env.ENV) })
- 在 main.js 中就可以区分是开发环境还是生产环境了:
if(ENV == 'DEV') { require('pages/html/page1.html') }
四、ES2015 && babel
如果你要在 webpack 中配置 ES2015 的开发环境,需要 babel 的帮助:
- babel-core
- babel-loader
- babel-preset-es2015
- babel-preset-stage-0
- babel-plugin-add-module-exports
- babel-plugin-transform-runtime
cd 4_es2015 npm install npm run dev
然后在 webpack.config.js
中:
{
test: /\.js$/,
loader: "babel",
exclude: /node_modules/
}
注意 exclude: /node_modules/
很重要,否则 babel 可能会把 node_modules
中所有模块都用 babel 编译一遍!
并且,在根目录下新建 .babelrc:
{
presets: [
"es2015",
"stage-0"
],
plugins: [
"transform-runtime",
"add-module-exports"
]
}
然后我们就可以写我们可爱的 ES2015 了:
import './style.css'
import { log } from '../common/index.js'
五、引入库
cd 5_library
npm install
npm run dev
CommonsChunkPlugin
CommonsChunkPlugin 是 webpack 自带的插件,能够把公有模块提取出来:
plugins: [
new webpack.optimize.CommonsChunkPlugin('common','common.js')
]
在 HtmlWebpackPlugin
中加入 common/index.js
模块,我们就可以看到 common/index.js
模块被提取到了 common.js
中。否则的话,page1/main
和 page2/main
中都会打包 common/index.js
。
externals
实际开发中,我们还会在页面使用 -->