前言:本文基于weboack4.x,主要涉及webpack4 基本概念、基本配置和实际项目打包优化。关于概念方面参考官网,经常使用配置来自于网络资源,在文末有相关参考连接,实践部分基于本身的项目进行优化配置。javascript
定义编译打包入口文件。类型:字符串(单入口)、对象(多入口)css
entry: './src/index.js' // 等同于 entry: { main: './src/index.js' }
一、filename:[name]
: 对应着entry中对象的key[id]
: 内部的chumk id[hash]
: 每次打包编译的惟一hash,改动会影响整个项目的打包,缓存失效[chunkhash]
:对应着每一个入口文件计算而来的hash,惟一,文件之间互不影响[contenthash]
: contenthash = (moduleId + content) 生成的hash。同一文件中,修改某个module影响其余module。例如,js代码中引入css文件,修改js文件形成css文件的hash改变 html
二、path: 是配置输出文件存放在本地的目录,字符串类型,是绝对路径puclicPath: 对构建出的资源进行异步加载(图片,文件) 时候的路径前缀, 能够看做静态文件托管在cdn
三、chunkFilename: 决定了非入口(non-entry) chunk 文件的名称,如按需加载、异步加载vue
参考:从零搭建webpack4 之output输出java
rules 数组,包含多个处理文件的 loader 配置react
test:类型正则、字符串、数组。匹配文件
use:类型字符串、对象、数组【loader字符串或对象】。对选中的文件应用loader。webpack
对象中包含:loader、options:loader的具体配置参数、enforce: 改变该loader的执行的顺序【pre/post】
include: 指定须要处理的文件。类型:通常为路径、能够是数组类型。
exclude:排除不须要处理的文件。类型:通常为路径、能够是数组类型。
noParse: 排除对没有采用模块化的文件解析和处理,相似:jQuery。 类型:RegExp, [RegExp], function其中一个。
parser:能够更细粒度的配置哪些模块语法【AMD、CommonJS、ES6等】是否须要解析git
Plugin 是用来扩展Webpack 功能的,经过在构建流程里注入钩子实现,它为Webpack 带
来了很大的灵活性。主要在打包的某个阶段执行该插件,对文件进行处理,相似于钩子函数github
触发treeshking条件:
1.须要代码是es module规范的而且使用解构赋值的方式引入,
2.开启optimization.usedExports:true
来标记使用和未使用的模块,web
webpack4的mode设置为production,默认开启optimization.usedExports和使用代码压缩
注:
一、tree shaking 不能做用于有反作用side-effect的代码
若是全部代码没有反作用,在package.json 中添加
sideEffects: false
若是存在反作用代码/模块,
sideEffects: [ ".src/some-side-effectful-file.js", "*.css" ]
"side effect(反作用)" 的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局做用域,而且一般不提供 export。
二、不要意外地将 ES 模块编译成 CommonJS 模块。若是你使用 Babel 的时候,采用了 babel-preset-env 或者 babel-preset-es2015,请检查这些预置的设置。默认状况下,它们会将 ES 的导入和导出转换为 CommonJS 的 require 和 module.exports,能够经过设置.babelrc中 { modules: false } 选项来禁用它
devServer: { proxy: { '/api': { target: 'http://localhost:3000', pathRewrite: {'^/api' : ''} }, context: ['/api', '/online'], //匹配多个路径,同时代理到同一个站点 target: 'http://localhost:3000' }, hot: true, hotOnly: true }
把代码分离到不一样的 bundle 中,能够按需加载或并行加载这些文件
实现方式:
一、入口配置:entry 入口使用多个入口文件 =》 存在重复引用的模块
二、抽取公有代码:使用 SplitChunksPlugin 抽取公有代码,取代CommonsChunkplugin
webpack.config.js 配置: ``` optimizition: { splitChunks: { chunks: 'all' } } ```
三、动态加载 :动态加载一些代码 =》 ECMAScript 提案 的 import() 语法
方式1 + 方式2 须要配合使用,才能达到代码抽离的效果
prefetch(预取):未来某些导航下可能须要的资源
preload(预加载):当前导航下可能须要资源
import(/* webpackPrefetch: true */ 'LoginModel');
/ webpackPrefetch: true /:把主加载流程加载完毕,在空闲时在加载其余,等再点击其余时,只须要从缓存中读取便可,性能更好。推荐使用,提升代码利用率。把一些交互后才能用到的代码写到异步组件里,经过懒加载的形式,去把这块的代码逻辑加载进来,性能提高,页面访问速度更快。
/ webpackPreload: true /: 和主加载流程一块儿并行加载。
import() 异步加载加载的模块,开启代码分割后,会被单独打包在一个文件中
路由懒加载
const Login = () => import('./components/login')
模块异步加载
import(/* webpackChunkName: "vendor"*/ './page/vendor.js').then(({default: _}) => {// todo})
mini-css-extract-plugin 用于提取公共css,取代 webpack 3 的 extract-text-webpack-plugin
注:通常适用于生产环境,在开发环境会致使HMR功能缺失;在开发环境,使用style-loader
使用方式:
const MiniCssExtractPlugin=require('mini-css-extract-plugin') const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') // 代码压缩 // modules 中 // css,scss,sass,less { test:/\.(sa|sc|c)ss$/, use: [ process.env.NODE_ENV === 'development' ? 'style-loader': MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader' ] } optimization: { minimizer: [new OptimizeCssAssetsPlugin({})] }, //plugins中 new MiniCssExtractPlugin({ filename: "[name].css" })
防止第三方包屡次编译打包。 第一次打包时,把第三方模块单独打包生成一个文件 vendors.dll.js,以后在打包时就能够直接从 vendors.dll.js 中引入以前打包好的第三方模块
实现过程:
一、编写一个用于生成动态连接库的配置文件
二、运行生成动态连接库和对应的.mainfest.json映射文件
三、在webpack.config.js中使用动态连接库。这样第二次编译打包会从json文件中找相应的模块
webpack.dll.config.js
module.exports = { entry: { react: ['react'] //react模块打包到一个动态链接库 }, output: { path: path.resolve(__dirname, 'dist'), filename: '[name].dll.js', //输出动态链接库的文件名称 library: '_dll_[name]' //全局变量名称 }, plugins: [ new webpack.DllPlugin({ name: '_dll_[name]', //和output.library中一致,值就是输出的manifest.json中的 name值 path: path.join(__dirname, 'dist', '[name].manifest.json') }) ] }
webpack.config.js
plugins: [ new webpack.DllReferencePlugin({ manifest: require(path.join(__dirname, 'dist', 'react.manifest.json')), }) ],
提升webpack的构建(打包/build)速度
webpack 做为模块化打包工具, 经常使用来对项目进行打包进行本地调试和发布到线上,因此不管是本身在项目配置使用webpack仍是使用开发框架的脚手架进行开发,都须要区分开发和生产环境。在webpack4 的配置项中添加了 mode
属性,能够用来区分二者模式。
下面是开发和生产模式下一些默认配置和区别:
development 模式下,默认开启了NamedChunksPlugin 和NamedModulesPlugin方便调试,提供了更完整的错误信息,更快的从新编译的速度。
production 模式下,因为提供了splitChunks和minimize,代码就会自动分割、压缩、优化,同时 webpack 也会自动帮你 Scope hoisting 和 Tree-shaking
使用 webpack-bundle-analyzer, 可直观的看出打包后每一个模块所占比例和大小
使用方法:
2.在 package.json -> script 中添加启动命令
"analyz": "cross-env NODE_ENV=prodution npm_config_report=true npm run build"
3.在 webpack.pro.conf.js -> plugin 添加如下代码,能够改变启动时的端口等配置
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
new BundleAnalyzerPlugin({analyzerPort: 8089})
关于使用方法详细可参考:webpack实践-webpack-bundle-analyzer使用
import xxxx from '@componets/xxx' => const xxx = () => require('@componets/xxx')
对于一些相似antd、element-ui、eCharts等库,能够按需引入,没有必要全局引入,具体方法见官方文档
对于loadash等API依赖工具,结合lodash-webpack-plugin和babel-plugin-lodash,实现按需引入,把须要的API一次性引入,并挂载在全局上
// 从lodash 中统一引入你须要的方法 import _ from 'lodash' export default { cloneDeep: _.cloneDeep, debounce: _.debounce, throttle: _.throttle, size: _.size, pick: _.pick, isEmpty: _.isEmpty } // 注入到全局 import _ from '@helper/lodash.js' Vue.prototype.$_ = _ // vue 组件内运用 this.$_.debounce()
对于相似Jquery等大而使用较少的库,能够在index.html使用cdn引入;若是顾虑到可能形成外部攻击等问题,能够下载成为本地资源,再引入
一、缩小文件搜索范围或者指定特定的文件夹位置
二、排除不须要进行处理的文件
......
不使用默认的 UglifyJs,使用并行压缩工具 webpack-parallel-uglify-plugin
......
具体参考:webpack 打包优化之速度篇
我是在我以前开发一大型项目使用webpack进行项目优化
注:此项目使用的webpack版本为2.x,不是最新版本4.x,因为项目比较复杂,升级带来的潜在问题可能比较多,时间精力有限,暂时未升级
项目技术和库:vue全家桶 + vue-cli + webpack + jQuery + element-UI + eCharts ...
按照上文中的经常使用配置,就打包速度和体积进行了优化,从而致使页面加载速度获得必定提高
图片上传失败,显示不出来 【手动捂脸】
因为本文参考了许多相关文章,并加以本身的理解和实战,若有不妥之处,请多包涵并指出,谢谢
参考:
webpack实践——webpack-bundle-analyzer 的使用
从基础到实战 手摸手带你掌握新版Webpack4.0详解 教你看文档
webpack 4.0 基础到实战配置github
webpack 官方文档
关于webpack的面试题总结