基于 Webpack 的 Web 应用构建与打包基础
Webpack 作为模块打包工具,极大地简化了前端的开发打包流程,笔者认为其为前端工程化做出了不可磨灭的贡献。2017 年初,Webpack 2.2 正式版本发布,相较于 1.0 版本中不论在社区文档还是功能实现上都有了长足的进步。Webpack 同时担负着构建系统与模块打包的功能,Webpack 会将你的所有的资源当做模块进行处理。Webpack 会将所有的资源文件,包括样式文件、图片等进行统一导入:
import stylesheet from 'styles/my-styles.scss';
import logo from 'img/my-logo.svg';
import someTemplate from 'html/some-template.html';
console.log(stylesheet); // "body{font-size:12px}"
console.log(logo); // "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5[...]"
console.log(someTemplate); // "<html><body><h1>Hello</h1></body></html>"
市面上已经存在的模块管理和打包工具并不适合大型的项目,尤其单页面 Web 应用程序。最紧迫的原因是如何在一个大规模的代码库中,维护各种模块资源的分割和存放,维护它们之间的依赖关系,并且无缝的将它们整合到一起生成适合浏览器端请求加载的静态资源。这些已有的模块化工具并不能很好的完成如下的目标:
- 将依赖树拆分成按需加载的块 - 初始化加载的耗时尽量少 - 各种静态资源都可以视作模块 - 将第三方库整合成模块的能力 - 可以自定义打包逻辑的能力 - 适合大项目,无论是单页还是多页的 Web 应用
打包简单应用
使用 jQuery 与 Lodash
npm install imports-loader
// Given you have this file example.js
$("img").doSomeAwesomeJqueryPluginStuff();
// then you can inject the $ variable into the module by configuring the imports-loader like this:
require("imports-loader?$=jquery!./example.js");
// This simply prepends var $ = require("jquery"); to example.js.
Lodash 是非常不错的工具库,不过很多时候我们仅需要其一小部分功能,此时lodash-webpack-plugin就派上了用场:
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const config = {
plugins: [
new LodashModuleReplacementPlugin({
path: true,
flattening: true
})
]
};
Dev Server 与热加载
资源文件处理
...
module.exports = (env) => {
const cssLoaders = [
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 2,
sourceMap: true,
localIdentName: env.NODE_ENV === 'production'
? '[hash:base64]'
: '[name]__[local]___[hash:base64:5]',
},
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
{
loader: 'postcss-loader',
},
];
return ({
...
{
test: /\.(scss|css)$/,
use: env.NODE_ENV === 'production' ?
ExtractTextPlugin.extract({
use: cssLoaders,
fallback: 'style-loader',
}) :
[
{
loader: 'style-loader',
},
...cssLoaders,
],
},
...
构建优化
编译性能优化
From the talk:
**Consider providing a way to easily disable sourcemaps for dev builds.**Disabling sourcemaps saves us ~25% (~30s) off our longest webpack build. The trade-off is slightly more challenging debugging, sometimes.
**Parallelize UglifyJS. **Use whatever means necessary. The 1.x beta plugins provide both caching of previously-uglified files, and also the ability to farm out uglify to a worker farm.
babel-loader: Don’t forget to exclude
node_modules
from the loader!
For large projects, definitely consider using the cacheDirectory option to cache loader output to the filesystem between runs.
- **Parallelize building multiple webpack configs. **parallel-webpack is designed for this, and is pretty close to a drop-in replacement for webpack itself.
- HappyPack** …is the bee’s knees.** Farm out your heavy loader workloads to a worker farm. You won’t regret it.
From the audience:
- **Webpack DLLPlugin can provide big benefits. **We (I) tried this at Redfin before and apparently stopped digging too early. Definitely going to take another look.
- hard-source-webpack-plugin. I hadn’t heard of this one before. Caches intermediate work to disk somehow. Sounds really promising.
- webpack-dev-middleware** for lazy watch.** We built a homegrown “lazy watch” framework around webpack watch mode that’s pretty tightly coupled with what we do with React Server. We got a tip after the talk that webpack-dev-middleware might make a lazy watch implementation straightforward for other users.