Webpack

172 阅读2分钟

Loader file-loader 将引用文件(图片)移动到dist目录下

url-loader 将引用的图片转化成Base64打包到js文件中,可限定大小配置是否转换

style-loader,css-loader,sass-loader,postcss-loader

css-loader的配置 options: { importLoaders: 2 // 打包时也会执行下面两个loader }

css模块化 css-loader options: { modules: true } import style from './index.css' class名使用style.avatar

字体打包 file-loader

Asset Management 静态资源

SourceMap 源码映射,方便错误追踪,一般在开发环境中设置 可设置是否包括loader或module

devtool: 'inline-source-map'

source-map: 生成一个map文件保存信息 inline-...: 映射信息打包到js文件 cheap-...信息简略 eval-..打包速度最快

推荐 development: 'cheap-module-eval-source-map' production: 'cheap-module-source-map'

Hot Module Replacement 模块热更新

devServer: { hot: true, hotOnly: true // 若hot失效,会刷新页面 }

plugins: [ new webpack.HotModuleRplacementPlugin() ]

fn()

if (module.hot) { module.hot.accept('./main.js', () => { fn() }) }

Babel @babel/core babel-loader { test: /jsx?$/, loader: 'babel', options: { presets: [['@babel/preset-env', { targets: { chrome: '67' }, useBuiltIns: 'usege' // 只打包使用到的模块,按需引入,不必手动引入@babel/polyfill }]], plugins: [ // 开发库时,避免preset(如引用polyfill,全局变量的影响) // index.js中不需引入polyfill ['@babel/plugin-transform-runtime', { 'corejs': 2, // 按需打包 需安装 @babel/runtime-corejs2 'helpers': true, 'regenerator': true, 'useESModules': false }] ] } }

index.js imoport '@babel/polyfill' // 兼容低版本浏览器

================================================

Tree Shaking 只支持ES Module 去除未使用的模块 mode: 'production' // 生产模式下默认Tree Shaking

mode: 'development, optimization: { usedExports: true // 生产环境不需配置 }

配合 package.json { // 生产环境也需配置 "sideEffects": false // 对所有模块进行tree shaking 或 [*.css],对中括号中的文件不进行tree shaking }

===============================================

webpack-merge

clean-webpack-plugin new CleanWebpackPlugin(['dist'], { root: path.resolve(__dirname, '../') // 配置项目根目录, 默认webpack配置文件所在的目录 })

配置支持动态引入 babel-plugin-dynamic-import-webpack //不支持魔法注释 换官方插件 @babel/plugin-syntax-dynamic-import

================================================

Code Splitting 代码分割

// 同步 optimization: { splitChunks: { chunks: 'all' // 将node_modules引入的库单独打包 } }

// 异步 无需webpack配置 import(/* webpackChunkName: "lodash" */ 'lodash').then() // 使用魔法注释命名分割后的模块名

配置参数(还是看文档吧~~) optimization: { splitChunks: { chunks: 'all', cacheGroup: { // 组 ... } default: {

}
...

} }

chunks: all async 只对异步引入生效 inital 只对同步引入生效

minSize

maxSize 一般不配

minChunks: 1 至少使用1次

priority 分组的优先级,哪个组优先级高,就打包到哪个组 reuseExisttingChunk: true 重复使用已打包过的模块

=================================================

Lazy Loading 懒加载 await import()

=================================================

打包分析 github.com/webpack/analyse webpack --profile --json > stats.json

Bundle Analyse webpack-bundle-analyzer

=================================================

代码利用率/覆盖率 尽量多写异步代码

Preloading Prefetching import(/webpackPrefech: true/, 'click.js')

==================================================

CSS文件代码分割 { use: [ MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader' ] }

new MiniCssExtractPlugin({ filename: '[name].css', chunkFilename: '[name].chunk.css' })

注意:tree-shaking干掉css package.json { sideEffects: ['*.css'] }

压缩 optimize-css-assets-webpack-plugin optimization: { minimizer: [new OptimizeCssAssetsWebpackPlugin({})], }

=============================================================

浏览器缓存(Caching) output: { filename: '[name].[contenthash]js' chunkFilename: '[name].[contenthash]js' }

老版本webpack mainfest差异 optimization : { runtimeChunk: { name: 'runtime' } }

==============================================================

Shimming 垫片

new webpack.ProvidePlugin({ : 'jquery' // 业务代码使用''时,会帮助引入jquery })

// 将this指向window loader: imports-loader?this=>window

===============================================================

环境变量 package.json --env.production

webpack.config module.exports = (env) => { if (env.production) { return merge(commonConfig, config) } }

=====================================================

Library的打包

package.json { name: "haha" mian: "./dist/index.js" }

webpack.config.js { externals: ['lodash'], // 打包时忽略已安装的库 output: { library: 'library' // 支持全局引入 全局变量名: library libraryTarget: 'umd' // 引入的方式配置 import require } }

======================================================

PWA 一种技术,当服务器挂了,网站再次访问,页面依然能展示

workbox-webpack-plugin

======================================================

TypeScript

{ test: /.(ts|tsx)$/, use: 'ts-loader', exclude: /node_modules/ }

tsconfig.json { "compilerOptions": { "outDir": "./dist", "module": "es6", "target": "es5", "allowJs": true } }

=======================================================

WebpackDevServer 请求转发

devServer: { proxy: { '/api': 'http: .../api', '/api2': { target: '...', pathRewrite: { 'a.json': 'b.json' }, changeOrigin: true } } }

https secure: true

========================================================

WebpackDevServer 开发环境解决单页面路由问题

url请求时,服务器没有对应的请求路径 historyApiFallback

devServer: { historyAPiFallback: true // 相当于把所有的路由请求都指向index.html }

生产环境 需后端处理

========================================================

ESLint .eslintrc.js { extends: 'airbnb' // 规范(较严) parser: 'babel-eslint', rules: {

}, globals: { document: false // document可作为全局变量 } }

vscode插件 ESLint

webpack loader的执行顺序是从后往前 { { test: /.js$/, use: [ 'babel-loader', { loader: 'eslint-loader', // 一般不用这个loader,会降低打包速度 options: { fix: true, // 自动修复 } } ] }

devServer: { overlay: true // 在窗口显示eslint错误信息 } }

最佳实现: 使用 git 钩子 eslint src

===========================================================

webpack 性能优化

提升打包速度

  • 升级工具

  • 尽可能少的模块上应用Loader 合理使用include exclude

  • Plugin 尽可能精简并确保可靠 如:开发环境不需代码压缩、选择官方推荐的插件

  • resolve 参数合理配置(不宜配置太多) resolve: { extensions: ['.js', '.jsx'] // 支配只逻辑文件,不宜配置(css, png等) mianFiles: ['index', 'child'] // 引入目录时,默认引入index或child文件,不宜配置会降低性能 alias: { // 别名 '@': path.resolve(__dirname, '../src') } }

  • dll 第三方模块只打包一次 webpack.dll.js { entry: { vendors: ['react', 'react-dom', 'lodash'], output: { filename: '[name].dll.js', path: path.resolve(__dirname, '../dll'), library: '[name]', } }, plugins: [ new webpack.DllPlugin({ // 生成映射文件 path: path.resolve(__dirname, '../dll/[name].manifest.json') }) ] }

    add-asset-html-webpack-plugin webpack.config { plugins: [ new AddAssetHtmlWebpackPlugin({ filepath: path.resolve(__dirname, '../dll.vendors.dll.js') }), new webpack.DllReferencePlugin({ // 使用映射文件 manifest: path.resolve(__dirname, '../dll/vendors.manifest.json') }) ] }

    // 动态使用dll,使用node const files = fs.readdirSync(path.resovle(__dirname, '../dll')) files.forEach(file => { if (/..dll.js/.test(file)) { plugins.push(new AddAssetHtmlWebpackPlugin({ filepath: path.resolve(__dirname, '../dll', file) })) } if (/..manifest.json/.test(file)) { new webpack.DllReferencePlugin({ manifest: path.resolve(__dirname, '../dll', file) })) } })

  • 控制包文件大小

  • thread-loader, parallel-webpack, happypack 多进程打包

  • 合理使用 sourceMap

  • 结合 stats 分析打包结果

  • 开发环境内存编译 无用插件剔除

=============================================================

多页面打包

{ entry: { main: './src/index.js', list: './src/list.js' }, plugins: [ new HtmlWebpackPlugin({ template: 'src/index.html' filename: 'index.html, chunks: ['runtime', 'vendors', 'main'] }), new HtmlWebpackPlugin({ template: 'src/index.html' filename: 'list.html, chunks: ['runtime', 'vendors', 'list'] }) ] }

自动化 config.plugins = (configs) => {

}