webpack是什么?
- Webpack模块打包工具,它会分析模块之间的依赖关系,然后使用loaders处理它们,最后生成一个优化并合并后的静态资源。
webpack之entry
- 可以通过在 webpack 配置中配置 entry 属性,来指定一个入口起点(或多个入口起点)。
- 单文件写法
entry: './path/to/my/entry/file.js'
- 多文件形式打包(object形式)
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
webpack之output
- 配置 output 选项可以控制 webpack如何向硬盘写入编译文件。
注意,即使可以存在多个入口起点,但只指定一个输出配置,属性功能如下。
- filename
filename:'[name].js' //导出的文件名字
- path
path:path.resolve(__dirname,'dist') //导出的文件存放位置
- publicPath
publicPath:'http:cdn.com.cn' //给每个js文件设置一个公共头部,打包出来后每个文件就是 http:cdn.com.cn/[name].js
webpack之热更新
1.webpack-dev-server
不刷新浏览器,不输出文件,而是放在内存中,使用HotModuleReplacementPlugin插件
- 只用于开发环境中:devServer,开启一个web服务器,简要配置已以及属性功能如下
devServer:{
contentBase:'./dist', //打开文件的目录
open:true, //自动打开浏览器
port:8010, // 打开端口号
proxy:{
'/api':'http://localhost:30000' //反向代理,解决跨域问题
},
hot:true, //自动刷新
hotOnly:true
},
2.webpack-dev-middleware
- 将webapck输出文件传输给服务器,适用于灵活的定制场景
3.webpack热更新原理的实现
A->B是首次编译过程。1—>2—>3->4 是文件改动后热更新过程
webpack之mode
- development:开发模式,不进行压缩代码
- production: 生产模式,会压缩代码
webpack之devtool:
- 是一个帮助我们调试的工具,可以选择一种 source map 格式来增强调试过程。不同的值会明显影响到构建(build)和重新构建(rebuild)的速度,官网链接。
- 配置格式以及部分source map值说明如下:
devtool:'cheap-module-eval-source-map',
/**
* none不提示哪里错了
* source-map 是一个映射关系,定位错误。
* inline-source-map 在行内添加映射关系
* cheap-source-map 提高打包速度,只报业务代码错误,错误只是精确到某一行
* cheap-module-source-map 包含业务代码和第三方插件错误都会报,错误只是精确到某一行
* eval 执行效率最快,不适合复杂的代码
*/
- 最佳实践 传送门
- 开发环境
devtool:'cheap-module-eval-source-map',- 生产环境
devtool:'cheap-module-source-map',
webpack之plugins
- plugins是插件,用来强大webpack的功能,通俗的来说就是可以在webpack运行到某些时刻自动的帮你干一些事情。
注:使用plugins前记得先 require() 入相应的plugin
- 常用的plugins如下:
- 举例:
plugins: [
new CleanWebpackPlugin(), //在每一次打包之前把打包目录清空,如将dist文件清空
new HtmlWebpackPlugin({ //会在打包结束后,自动生成一个html文件,并把打包的js自动引入到文件中
template:'src/index.html'
})
],
webpack之loaders
- webpack 可以使用 loaders 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源,他是一个函数。loaders有很多,常用的如下:
-
这里简要的举例几个常用的。
- babel-loader
注:业务代码开发记得在打包入口文件中引入import "@babel/polyfill",如果是开发一个组件库或者一个类库则不需要,因为polyfill的方法注入是全局的。可以使用@babel/plugin-transform-runtime 插件,会以闭包的形式引入;
{ test: /\.js$/, //指定匹配规则 /** * exclude:表示不会对node_modules里面的东西进行转义为es6,加快打包速度 */ exclude: /node_modules/, loader: "babel-loader", //使用的loader名 options:{ //这部分也可以放在.babelrc文件中 "presets": [ [ "@babel/preset-env", { /** * 指定版本进行es6->es5 */ "targets": { "edge": "17", "firefox": "60", "chrome": "67", "safari": "11.1" }, "useBuiltIns": "usage" //只把需要的业务代码进行转化,可以大大的减小打包体积 } ], "@babel/preset-react" //用于react项目 ] } }- url-loader
- url-loader和file-loader功能是相似的,可以处理图片和字体,url-loader可以设置较小的资源自动base64
{ test:/\.(png|jpg|gif)$/, use:{ loader:'url-loader', options:{ /** * name:打包后的图片名字 * limit:将小于2048kb的图片转为base64,可以较少网络请求,将大于2048kb的图片放入到images/ * outputPath:图片文件打包后的存放目录 */ name:'[name].[ext]', outputPath:'images/', limit:2048 } } },- postcss-loader
- 自动给css添加浏览器前缀,比如-webkit-。可以直接在option中配置,也可以在postcss.config.js中配置。 以下示例在postcss.config.js中配置
module.exports = { plugins:[require('autoprefixer')({ overrideBrowserslist: [ 'last 10 Chrome versions', 'last 5 Firefox versions', 'Safari >= 6', 'ie> 8' ] })] } - css-loader
- css-loader用于将.css文件,并转化为common.js文件。style-loader将样式通过
<style>标签插入到head中
- css-loader用于将.css文件,并转化为common.js文件。style-loader将样式通过
{ test: /.css$/, use: [ 'style-loader',//loader 链式调用的顺序是从右到左,先是 css-loader, 再是 style-loader 'css-loader' ] }, { test: /.less$/, use: [ 'style-loader', 'css-loader', 'less-loader' ] } }webpack之文件监听
缺陷:每次更新后都需要开发者手动更新浏览器
- 文件监听是指在发现源代码发生变化是,自动构建出新的输出文件
- 文件监听的方式有两种: - 启动webpack命令时,带上watch参数 - 在配置webapck.config.js是,设置watch:true
modeule.export={ //默认是false watch:true, watchOptions:{ ignored:/node_modules,//默认为空,设置不监听的文件或文件夹 aggregateTimeout:300,//监听到变化后会等300ms后再去执行,默认300ms poll:1000 //判断文件是否发生变化,系统每隔1000ms去访问一次 } }webpack之tree sharking
Tree Shaking 只支持ES MOdule形式,他可以把你 import 入但是没有使用的代码移除,就想摇树一样,把一些不需要的东西摇落在地上。
- sideEffects
- 在一个纯粹的 ESM 模块世界中,识别出哪些文件有副作用很简单。然而,我们的项目无法达到这种纯度,所以,此时有必要向 webpack 的 compiler 提供提示哪些代码是“纯粹部分”。比如我们再一个文件中 import style.css ,作用于这个文件的样式,但是并不会在代码的引用,但是tree sharking 是会认为这个是无用代码移除,此时我们便可以再 package.json中配置sideEffects 来避免样式移除。
"sideEffects": [ "*.css" ],
webpack之代码分离
/** * 代码分割,优化加载速度 * runtimeChunk:用于放置 业务代码和node-modules之间关联的代码,一个非常好的优化的点。 * chunks:async 表示只对异步代码生效 all对异步同步都生效 * minSize 大于这个值会做代码分割 * minChunks:打一个模块至少用多少次的时候才做代码分割 * maxAsyncRequests: 同时加载的模块数 * maxInitialRequests: 入口文件最多分割模块数 * automaticNameDelimiter: 打包后文件的名字连接符 * name:true cacheGroups里的名字生效 * cacheGroups 分割出来的代码分割到哪里去,比如,jquery lodash等引入在node-modules 都打包到vendors.js * priority值越大,优先级越高,cacheGroups和default用哪个决定于priority值 * reuseExistingChunk:如果一个模块已经被打包了,后续会忽略 */ optimization:{ runtimeChunk:{ name: 'runtime' }, usedExports:true, splitChunks:{ chunks: "all" minSize: 30000, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, automaticNameDelimiter: '~', name: true, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true } } } }webpack之缓存
- 通过使用 output.filename 进行文件名替换,可以确保浏览器获取到修改后的文件.[hash] 替换可以用于在文件名中包含一个构建相关(build-specific)的 hash,但是更好的方式是使用 [chunkhash] 替换,在文件名中包含一个 chunk 相关(chunk-specific)的哈希,这样只要每次hash值没变的文件,浏览器就可以从缓存中去找,对一些第三方库非常友好。
output:{ filename:'[name].[contenthash].js', chunkFilename:'[name].[contenthash].chunk.js', path:path.resolve(__dirname,'../dist') }webpack之shimming
- webpack 编译器(compiler)能够识别遵循 ES2015 模块语法、CommonJS 或 AMD 规范编写的模块。然而,一些第三方的库(library)可能会引用一些全局依赖(例如 jQuery 中的 $)。这些库也可能创建一些需要被导出的全局变量。这些“不符合规范的模块”就是 shimming 发挥作用的地方。
plugins: [ new webpack.ProvidePlugin({ $ : 'jquery', _: 'lodash' }) ]webpack之alias
- 在webpack.config.js中,通过设置resolve属性可以配置查找“commonJS/AMD模块”的基路径,也可以设置搜索的模块后缀名,还可以设置别名alias。设置别名可以让后续引用的地方减少路径的复杂度。
resolve: { alias: { "@": resolve("../src"), // 这样配置后 @ 可以指向 src 目录 }, },webpack之环境变量
- env是环境变量,在package.json中配置不同的值
// package.json // --env.production 表示在运行 build 命令时,将env.production设置为true "scripts": { "dev": "webpack-dev-server --inline --config ./build/webpack.common.js", "build": "webpack --env.production --config ./build/webpack.common.js" } // webpack.common.js // 在webpack.common.js 中我们可以这么拿 env 来判断 module.exports=(env)=>{ if(env && env.production){ return merge(commonConfig,prodConfig) }else{ return merge(commonConfig,devConfig) } }webpack之单页面路由问题
- 当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 index.html。通过传入以下启用
historyApiFallback: truewebpack性能优化之打包速度
- 升级webpack或者升级node、npm、yarn
- 减少loader的作用范围和使用
rules:[ { test: /\.js$/, exclude: /node_modules/, //这里就不会对node_modules里的东西进行es6转换 loader: "babel-loader" }, - 合理的利用plugin,使用官方社区推荐的插件(比如代码压缩,开发环境就不需要这个插件)
webpack性能优化之合理配置resolve
resolve: { extensions: ['.js', '.vue'],//在import文件时可以省略写.js,.vue alias: { 'vue$': 'vue/dist/vue.common.js',//起别名,可以文件引入时直接使用 'src': path.resolve(__dirname, '../src'), 'assets': path.resolve(__dirname, '../src/assets'), 'components': path.resolve(__dirname, '../src/components'), 'common': path.resolve(__dirname, '../src/common'), 'img': path.resolve(__dirname, '../resource/img') } } - babel-loader