webpack.config.js 文件解析
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ClearWebpackPlugin = require('clear-webpack-plugin') module.exports = {
mode: 'development', // 打包模式 测试环境/生产环境
devtool: 'cheap-module-eval-source-map', // 是否打包SourceMap文件, 映射代码错误位置
// 打包入口配置
entry: {
main: './src/index.js',
},
// 使用webpack-dev-server 插件,实现监听代码改动自动打包
devServer: {
contentBase: './dist', // 监听变化的文件
open: true, // 是否自动打开浏览器
port: 8080, // 监听的端口
hot: true, // 是否启动模块代码热更新
hotOnly: true, // 是否只刷新一次浏览器
},
// 配置编译的各模块 loader
module: {
noParse: /es6-promise\.js$/, // avoid webpack shimming process
rules: [
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [path.resolve(__dirname, '../src/')],
options: {
formatter: require('eslint-friendly-formatter')
}
},
// 使用 babel 把ES6转换成ES5 ,需要配合 @babel/preset-env
// 配置ES6转换成ES5过程中,按需补充必要代码,在js文件中,需要引入 @babel/polyfill 插件,或者使用 @babel/plugin-transform-runtime
{
test: /\.(js|es6)$/,
loader: 'babel-loader',
exclude: /node_modules/, // 表示除了该文件外
options:{
presets: [['@babel/preset-env', {
useBuiltIns: 'usage'
}]]
},
},
]
},
// 编译输出配置
output: {
path: path.resolve(__dirname, '../dist2'), // 输出目录
publicPath: '/gsh/dist/', // 输出目录添加地址前缀
filename: '[name].[chunkhash].js' // 编译后输出的文件名称
},// 使用 plugins 插件,实现编译过程中自动使用某个 html模板,以及编译前清除dist里的文件
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html', // 使用某个 html模板
}),
new ClearWebpackPlugin(['dist']), // 编译前清除dist里的文件
new webpack.HotModuleReplacementPlugin(), // 使用HMR实现模块代码热更新
],
}
在生产环境和开发环境中,webpack的配置是有所区别的,可以把相同部分提取出来作为 common.js ,最后使用 webpack-merge 插件进行合并
Tree Shaking
含义为 ’摇树‘ ,其作用是在打包过程中,去除某些在项目中并没有引用的模块, 只支持 ES Module 方式, 即 import
某些在代码中引入的模块,假如在逻辑中没有使用到,那么在最后打包中不会被打包进去。
在 development 模式下,在webpack.config.js 文件中添加下列配置:
optimization:{
usedExports: true,
}
在 package.js 文件中添加下列配置,表示除了某个文件外进行 Tree Shaking :
"sideEffects": ['*.css', '@babel/pollyfill'] // 表示遇到这两个模块忽略,可取值为 false
打包分析
可以使用webpack 官方提供的工具进行打包分析, 打开链接 https://github.com/webpack/analyse 查阅文档, 点击 analyse 位置进入分析工具,上传 stats.json 文件
在打包的时候,生成 stats.json 文件, 生成方法为 : 在 package.json 文件打包命令中添加 --profile --json > stats.json
"scripts": { "build": "webpack --profile --json > stats.json --config ./build/webpack.dev.js", },
也可以采用 webpack 提供的图形化分析工具 https://wenpack.js.org/guides 选择 Code Splitting 目录下的 Bundel Analysis
Code Splitting 代码分割
根据代码的应用场景和逻辑,打包的时候自动将代码分割成多个 JS 文件, 避免过大的JS 文件出现,提升页面渲染速度
同步代码分割,在webpack.config.js 文件中添加下列配置:
optimization:{
splitChunks: {
chunks: 'all' // 开启代码分割
}
}
异步代码(import):无需任何配置,webpack会自动进行代码分割
chunks 取值 all , 表示同步代码和异步代码都进行代码分割, 默认取值是 async , 表示只对异步代码进行分割
关于代码分割,webpack 推荐使用的是 async 的方式,这个涉及到页面的代码使用率,在浏览器控制台中, 使用 command + shift + p 的方式,搜索 Coverage 查看页面代码使用率
对于页面渲染速度的优化,使用代码缓存,并不能解决首屏加载速度的问题,应该尽量提升页面代码使用率,对于暂未使用到的代码逻辑,采用懒加载的方式。如页面调用的某个方法,方法内的逻辑在未被调用时就是多余的,可以采用异步的方法进行懒加载。
使用 webpack 里的 Prefetching / Preloading实现代码的懒加载 , 在引入代码逻辑的时候添加 /*webpackPrefetch: true*/
例子:将某个方法里的逻辑 导出, 在调用时再作为模块导入
// 新建 click.js 文件,将方法的执行逻辑导出
function handleClick() {
const el = document.getElementById('test')
el.innerHTML = '点击页面后生成'
} export default handleClick; // 在 main.js 文件中,方法导入执行逻辑
document.addEventListener('click', () => {
import(/*webpackPrefetch: true*/ './click.js').then(({default: handleClick}) => {
handleClick()
})
})
PWA
全称 Progressive Web Application , 这是一项新的技术,可以在用户进入页面的时候,缓存页面内容。当服务器故障后,用户重新进入这个页面的时候,可以利用缓存正常显示页面。
在webpack 里,可以使用 workbox-webpack-plugin 插件实现。
const WorkboxPlugin = require('workbox-webpack-plugin') // 在 plugins 添加下列配置
new WorkboxPlugin.GenerateSw({
clientsClaim: true,
skipWaiting: true
})
VUE 多页面打包webpack配置
/** 修改entry配置项 */
entry: {
style: './src/style/app.scss', // 不变
app: './src/main.ts', //不变, 这个是index.html的组件
analysis: './src/analysis.ts'
// analysis是新增的模块名字(名字自定义,项目中因为是分析界面模块所以取名为为analysis)
// 如果还有多个其他页面,可以继续添加模块。。。
// P.S. 注意是模块不是组件,例如个analysis模块中实际包含ValueAnalysis,ValueAnalysisBar,ValueAnalysisType等组件,但是不必引入。
// P.S. 最后build打包的时候记得放出所有的模块
}
/** 和main.src同级,创建analysis.ts文件,注意文件名字是对应上面的./src/analysis.ts文件 */
// analysis.ts
import Vue from 'vue' // register plugins hooks fo vue component
import 'common/registerHooks' import * as svgicon from 'vue-svgicon'
// import all icons
import 'components/icons' import App from 'pages/App' Vue.use(svgicon, {
tagName: 'icon'
}) new Vue({
el: '#app',
render: h => h(App)
}) // 内容基本上和main.src一样, 但是注意router有所变化,这里router导入了一个新的路由文件routerAnalysis
// 配置build中的文件输出路径,当然也可以不配置然后在下一步中直接书写文件路径,但是统一比较方便维护
build: {
index: path.resolve(__dirname, `../../dist/${env}/index.html`), // 默认的
analysis: path.resolve(__dirname, `../../dist/${env}/analysis.html`), //新加的模块 ...
...
// 其他配置项不变
}
/** 用HTMLWebpackPlugin生成多个文件 */ // 原本的htmlWebpackPlugin配置
new HtmlWebpackPlugin({
filename: config.build.index,
template: 'build/tpl/index.html',
inject: true,
dllName,
assetsPublicPath: config.build.assetsPublicPath,
staticHost: '',
minify: {
removeComments: true,
collapseWhitespace: true
},
excludeChunks: ['analysis'], // index.html没有用到analysis模块的内容
chunksSortMode: 'dependency'
}),
// 想要生成多少不同的html就配置多少个new HtmlWebpackPlugin
new HtmlWebpackPlugin({
filename: config.build.analysis, // 生成的新的文件位置,步骤4中配置的路径
template: 'build/tpl/index.html', // html依据模板,可以沿用index.html或者另外写一个,看具体需求
inject: true,
dllName,
assetsPublicPath: config.build.assetsPublicPath,
staticHost: '',
minify: {
removeComments: true,
collapseWhitespace: true
},
excludeChunks: ['app'], // 该模块没有用到app模块中的组件
chunksSortMode: 'dependency'
}),