开发环境性能优化php
生产环境性能优化css
优化打包构建速度html
HMRvue
优化代码调试node
source-mapreact
❝概念:「HMR:」 hot module replacement 热模块替换 / 模块热替换jquery
❞
做用:一个模块发生变化,只会从新打包这一个模块,而不是打包全部模块,极大的提高了构建速度webpack
样式文件:能够使用 HMR 功能:由于 style-loader 内部已经实现web
js 文件:默认不能使用 HMR 功能:开启须要添加支持 HMR 功能的 js 代码,且只能处理 「非入口 js 文件」(入口文件将其它文件所有引入,若添加,会致使所有从新加载)npm
html 文件:默认不能使用 HMR 功能,同时会致使 「html 文件不能热更新」了
解决:修改 「entry」 入口,将 html 文件引入
module.exports = { // 引入html,解决热更新的问题 entry: ['./src/js/index.js', './src/index.html'], devServer: { // 开启 HMR 功能 // 当修改了 webpack 配置,新配置要想生效,必须重启服务 hot: true } }
❝概念:一种提供源代码构建后代码映射技术(若是构建后代码出错了,能够经过映射追踪到源代码错误)
❞
参数:[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
source-map
:外部(错误代码的准确信息 和 位置)
inline-source-map
:内联(只生成一个内联 source-map)(错误代码的准确信息 和 位置)
hidden-source-map
:外部(直接生成 .map
文件)(不能追踪源代码错误,只能提示到构建后代码的错误位置)
eval-source-map
:内联(每个文件都生成对应的 source-map,都在 eval)(错误代码的准确信息 和 位置)
nosources-source-map
:外部(错误代码的准确信息,没有源代码信息)
cheap-source-map
:外部(错误代码的准确信息 和 位置,但只能精确到行)
cheap-module-source-map
:外部(错误代码的准确信息 和 位置,会将 loader 的 source-map 加入)
开发环境:速度快,调试更友好。eval-source-map
/ eval-cheap-module-source-map
(vue 和 react 脚手架中默认使用:eval-source-map
)
速度快:(eval > inline > cheap > ...)eval-cheap-source-map
、eval-source-map
、
调试友好:source-map
、cheap-module-source-map
、cheap-source-map
生产环境:源代码要不要隐藏?调试要不要更友好?source-map
/ cheap-module-source-map
内联会让代码体积变大,因此在生产环境中只会只用 「外部 source-map」nosources-source-map
、hidden-source-map
module.exports = { mode: 'development', // 'production' devtool: 'eval-source-map' // 'source-map' }
优化打包构建速度
oneOf
babel 缓存
多进程打包
externals
dll
优化代码运行的性能
缓存(hash -> chunkhash -> contenthash)
tree shaking
code split
懒加载/预加载
PWA
❝oneOf:避免了每个文件都要被 loader 过一次 注:不能有两个配置处理同一种类型文件
❞
module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, //优先执行 enforce: 'pre', loader: 'eslint-loader', options: { fix: true } }, { // 如下 loader 只会匹配一个 oneOf: [ ..., {}, {} ] } ] } }
babel 缓存
让第二次打包构建速度更快
module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: [ // 开启 babel 缓存 // 第二次构建时,会读取以前的缓存 cacheDirectory: true } } ] } }
文件资源缓存
让代码上线运行缓存更好使用
hash:每次 webpack 构建时会生成一个惟一的 hash 值
问题:由于 js 和 css 是同时使用一个 hash 值(若是从新打包会致使全部文件缓存都失效)
chunkhash:根据 chunk 生成 hash 值。若是打包来源于同一个 chunk,那么 hash 值就同样
问题:js 和 css 的 hash 值仍是同样的
由于 css 是在 js 文件中被引入的,因此同属于一个 chunk
「contenthash」:根据文件的内容生成 hash 值。不一样文件的 hash 值移动不同
❝tree shaking:去除无用的代码
❞
前提:1. 必须使用 ES6 模块化;2. 开启 production 环境
做用:减小代码体积
在 package.json 中配置:
"sideEffects": false
全部的代码都没有反作用(均可以进行 tree shaking)
问题:可能会把 css / @babel/polyfill (反作用)文件干掉
sideEffects: ["*.css", "*.less"]
多入口形式:
module.exports = { entry: { // 多入口 main: './src/js/index.js', test: './src/js/test.js' }, output: { // [name]: 取文件名 filename: 'js/[name].[contenthash:10].js', path: resolve(__dirname, 'build') }, mode: 'production' }
optimization:
module.exports = { entry: './src/js/index.js',, output: { filename: 'js/built.[contenthash:10].js', path: resolve(__dirname, 'build') }, // 能够将 node_modules 中的代码单独打包一个chunk最终输出 optimization: { splitChunks: { chunks: 'all' } } mode: 'production' }
「某个文件的单独打包」
// import动态导入语法:能将某个文件单独打包成一个 chunk // 此处的注释能够命名打包后文件名 import(/* webpackChunkName: 'test' */ './test.js') .then(() => {}) .catch(() => {})
❝懒加载:当文件须要时才加载
❞
❝预加载 prefetch:会在使用前,提早加载 js 文件。等其余资源加载完毕,浏览器空闲了,在偷偷加载资源
❞
❝正常加载能够认为是并行加载(同一时间加载多个文件)
❞
// import动态导入语法:能将某个文件单独打包成一个 chunk // webpackChunkName 此处的注释能够命名打包后文件名,webpackPrefetch 预加载 import(/* webpackChunkName: 'test', webpackPrefetch: true */ './test.js') .then(() => {}) .catch(() => {})
❝PWA:渐进式网络开发应用程序(离线可访问)
❞
插件:workbox --> npm i workbox-webpack-plugin -D
module.exports = { plugins: [ new WorkboxWebpackPlugin.GenerateSW({ // 1. 帮助 serviceworker 快速启动 // 2. 删除旧的 serviceworker // 生成一个 serviceworker 配置文件 clientsClaim: true, skipWaiting: true }) ] }
注册 serviceworker,并处理兼容性问题
eslint 不认识 window、navigator 等全局变量
解决:须要修改 package.json 中 eslintConfig 配置
"env": { "browser": true }
sw 代码必须运行在服务器上
// 注册 serviceworker,并处理兼容性问题 if ('serviceworker' in navigator) { window.addEventListener('load', () => { navigator.serviceworker .register('/service-worker.js') .then(() => { console.log('sw注册成功了') }) .catch(() => { console.log('sw注册失败了') }) }) }
插件:npm i thread-loader -D
进程启动大概为 600ms,进程通讯也有开销。只有工做消耗品时间比较长,才须要多进程打包。
module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: [ // 开启多进程打包 'thread-loader', { loader: 'babel-loader', options: { presets: [] } } ] } ] } }
设置拒绝打包的库
module.exports = { externals: { // 忽略库名 --> npm包名 jquery: 'jQuery' } }
在入口 index.html 引入 CDN<script src="xxx"></script>
对代码进行单独打包,(第三方库:jQuery,react,vue ...),第二次之后打包时再也不打包第三方库。webpack.dll.js
文件:
注:运行 webpack 时,默认查找 webpack.config.js
,须要运行 webpack.dll.js 文件时,能够经过运行 webpack --config webpack.dll.js
实现运行
const { resolve } = require('path') const webpack = require('webpack') module.exports = { entry: { // 最终打包生成的[name] --> jquery // ['jquery'] --> 要打包的库是 jquery jquery: ['jquery'] }, output: { filename: '[name].js', path: resolve(__dirname, 'dll'), library: '[name]_[hash]' // 打包的库里面向外暴露的内容的名字 }, plugins: [ // 打包生成一个 manifest.json --> 提供和 jQuery 映射 new webpack.DllPlugin({ name: '[name]_[hash]', // 映射库的暴露的内容名称 path: resolve(__dirname, 'dll/manifest.json') }) ], mode: 'produciton' }
const { resolve } = require('path') const webpack = require('webpack') module.exports = { plugins: [ // 告诉webpack哪些库不参与打包,同时使用名称改变 new webpack.DllReferencePlugin({ path: resolve(__dirname, 'dll/manifest.json') }), // 将某个文件打包输出,并在html中自动引入 new AddAssetHtmlWebpackPlugin({ filepath: resolve(__dirname, 'dll/jquery.js') }) ], mode: 'produciton' }
◆ ◆ ◆ ◆ ◆
你的在看我当成喜欢