【Vue五分钟】五分钟了解webpack的高级概念

简介: 其实如果配置了 useBuiltIns 就不会需要再 import babel profill。 实际上目前的话虽然只是引入了某个模块的某个方法,在打 包还是会把模块的所有方法引入,最好是引入什么打包什么, 这就需要 tree shaking,摇掉不需要的内容。

1.Tree Shaking部分

其实如果配置了 useBuiltIns 就不会需要再 import babel profill。 实际上目前的话虽然只是引入了某个模块的某个方法,在打 包还是会把模块的所有方法引入,最好是引入什么打包什么, 这就需要 tree shaking,摇掉不需要的内容。 注意 tree shaking 只支持 ES 模块的引入。 如果想开启,在开发环境下添加↓即可。如下:

optimization: {
   usedExports:true
},

如此配置后引入如果并没有导出内容但是确实是有用的(如 profill)就会被直接忽略了,就会出错,所以才加上 sideEffects, 指定不需要 tree shaking 的文件,若是设置为 false,就全部 都要 tree shaking。 一般 css 也需要放进去。

"sideEffects":[
"*.css"
]

 当然了在开发环境下,tree shaking 并不会把代码直接从打包 后的 js 中剔除掉,只是提示一下,因为直接改的话 source map 映射就不对了,改为线上环境则会生效(而且 tree shaking

一些默认配置甚至已经写好了,都不用写,直接改个环境就 行)。

2.Development和Production模式的区分打包

 开发环境 source map 比较全,但是线上就简洁。 开发环境代码一般不压缩,线上则压缩。 如果切换环境要一直更改 webpack.config.js 文件则比较麻烦, 可以复制拆成 dev、prod 两个 js 文件

"script": {
   "dev":"webpack-dev-server --config webpack.dev.js",
"bulid":"webpack -- config webpack.prod.js"
},

当你开发完成并打包线上环境代码,形成文件,放到服务器,和后端相互结合就可以了;但是是这样子存在大量重复的代码,我们可以创建一个webpack.common.js文件存放共同的代码。

const HtmlWebpackPlugin = require('html-webpack-plugin ' );
const CleanwebpackPlugin = require( 'clean-webpack-plugin' );
module.exports = {
entry: {
main:'./src/ index.js·},

然后依靠一个第三方模块 webpack-merge,在导出的时候合 并配置即可,

const merge = require( 'webpack-merge');
const commonConfig = require( './webpack.common.js ');
const prodConfig= {
mode: 'production' ,
devtool: 'cheap-module-source-map'}
module.exports = merge( commonConfig, prodConfig);
const webpack = require( 'webpack' );
const merge = require( 'webpack-merge ' );
const commonConfig = require( ' ./webpack.common.js ');
const devConfig = {
mode: 'development',
devtool: 'cheap-module-eval-source-map ' ,devServer: i
contentBase: './dist',open: true,
port: 8080,hot: true3,
plugins:[
new webpack.HotModuleReplacementPlugin(],
optimization: {
usedExports: true}
}
module.exports = merge( commonConfig,devConfig);

3.webpack和codesplitting

Code splitting 就是代码分割。 注意 clean 插件会以 webpack.config.js 所在目录为根目录,也 就只能清除根目录下面的内容,无法清除根目录外的内容, 不过我们可以添加一个 root 参数重新指定根路径。

plugins: [
new HtmlwebpackPlugin({
template: 'src/index.html'}),
new cleanWebpackPlugin(['dist'l,{
root: path.resolve(_ dirname, '../')})
],
output: {
filename: '[name] .js ',
path: path.resolve(_dirname, '../dist ')}

当我们引入一个工具库,且在下面写了非常多业务逻辑,目 前最终也是打包到一个文件中,当然无异常,只是这个 js 文 件会非常大,用户需要等到这个文件加载完成;另外如果只 是简单的改变了一点业务逻辑,用户又需要重新加载这个文 件。可以通过在其它文件引入工具库,挂载到 window 就能在其 它文件中使用该库,然后其它文件就写业务逻辑,当然入口 要 2 个。

 如此就换了一个打包方式(将单文件拆成几个文件),打包 后会生成两个 JS 文件,浏览器可以并行加载,可能会比单独 加载一个大文件要快一些,同时业务逻辑变更也只是需要加 载业务逻辑文件。 这种拆分公用部分代码的做法就是 code splitting,这个其实 与 webpack 没有任何关系,是我们自己拆分,当然了 webpack 现在内置有处理拆分代码的插件,就捆绑到一起了,拆分变 得更加简单。 目前简单配置如下↓,打包后会有 main.js(只有业务逻辑了) 和 vendors-main.js(提取了类库的代码),因为这是同步的模 块引入,可以分析提取。

entry :{
  main:'./src/index.js'
}
optimization: {
splitChunks:{
chunks: 'all'}
},

但是如果是异步加载呢(需要先安装处理异步语法的 babel, 因为还是实验性质语法),打包后依然只是index放业务逻辑,0.js 放类库。也就是说异步加载可以不写 optimization 配置, 也能实现代码分割。

function getcomponent( {
return import( ' lodash' ).then(({ default: -})=>{
var element = document.createElement('div');.element.innerHTML = _.join(['Dell', ‘Lee'],'-');return elepent;
})
}
getcomponent( ).then(element>i
document. body-appendChild(element);})

4.splitChunksPlugin配置参数

目前打包异步代码生成的文件名是以 id 命名,如果想自定义 名字可以采用魔法注释命名;

function getComponent() {
return import(/* webpackCbunkName: "lodash"*/ 'lodash ")
element.innerHTML = _.join( I'Dell',‘Lee']','-');return element;
})

当然了之前安装的处理异步第三方插件不支持魔法注释,需要换一个官方的。

presets: [
"@babel/preset-env",{
targets: {
chrome: "67",},
useBuiltIns: 'usage'}
],
"@babel/preset-react"],.t,-1..
piugins: ["@babel/plugin-syntax-dynamic-import"]}

最终生成的文件名就是 vendors~lodash.js,当然了如果想去 掉 vendors 可以修改 splitChunks 的参数。

optimization: {
splitChunks: {
chunks: 'all',cacheGroups: {
vendors: false,defadlt: false}
}

不管是同步异步都最好使用配置,而且配置都对它们有效。

 

optimization: i
splitChunks: {
chunks: 'async'minSize: 3000o,|maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,maxInitialRequests: 3,
automaticNameDelimiter: '~',name: true,
cacheGroups: i
vendors: false,default: false}
}},

Chunks 参数代表是对同步/异步/全部代码生效,比如 async 就是只对异步代码有效

cacheGroups: i
vendors: i
test: /[N/]node_modules [V/]/,priority:-10
},
default: false}

CacheGroups 是确定需要处理的代码(chunks 属性)后就走 到这里,test 检验是否是在 node 模块目录下(类库)引入, 是就可以分割,并且归于 vendors 这个组(这就是代码会有 vendors 前缀),也可以通过 filename 属性自定义打包后的名 字。minSize 是引入的类库,大于这个值才做代码分割(这里就是 30kb)。

 CatchGroups 中的 default 就是处理没有任何组接收的文件, 因此自定义的模块就是写到 default~main.js,当然也还是可 以 filename 自定义名字,可以看到不管怎么说这些配置最终 都和 catchGroups 有关。 MaxSize 是对比较超过它的值尝试对代码进行二次拆分,拆 分 n 个该值大小的文件,基本不行,可以不配置。 MinChunks 就是代码至少被引入多少次才做代码分割。 MaxAsyncRequests 是最大同时加载的请求,也就是最多拆分 多少个。

5.Lazy Loading懒加载

之前写成异步加载的模式就是为了能够懒加载(异步加载模 块,什么时候真正执行该模块才加载该模块,具体是和 ES6 的实验性方法 import()有关,与 webpack 无关,只不过是 webpack 可以识别需要懒加载的模块)。

function getcomponent(O {
return import(/* webpackChunkName : "lodash"*/‘lodash')
var element =document.createElement ( 'div');._.);
return element;
})
}
document.addEventListener( 'click',O)=>{
getcomponent().then(element ->i
document.body -appendChild(element);});
})

如此就是一开始不会加载 lodash,除非点击了页面才会去加 载这个模块。 每一个 JS 文件都是一个 Chunk。可以直接按照以下配置即可(有默认值)↓

6.打包分析、preloading、prefetching

打包分析是分析打包后的文件,看看是否合理。 首先需要生成一个打包过程描述文件↓(--profile...json,也 就是把描述文件放到 stats.json 中)。然后需要开 webpack.github.io/analyse 工具网站,上传刚刚 的 json 文件。

2345_image_file_copy_375.jpg

当然了也还有其它很多可视化分析工具,比如 webpack-chart ( 以 图 表 的 形 式 分 析 json 文 件 ) 等 等 , 一 般 使 用 webpack-bundle-analyzer 比较多。 为什么一开始 webpack 对 chunks 默认值是 async?因为 all 的话其实是让第二次加载页面无需重复加载类库性能更高 而已,而 webpack 希望第一次就很快,则异步代码我们最好 放到一个模块里面去,然后再到需要的地方引用,当触发操 作需要使用该模块才加载。 Command+shift+p 输入 code coverage 可以录制页面,查看文件的命令使用情况(百分比),就是目前加载的内容执行了 多少。

  因此现在不再是去纠结缓存而是去看看文件的利用率,将一 开始没有用到的内容以异步的方式优化掉,性能才会更好, webpack 认为只有异步的代码(提高代码利用率)才能真正 提高性能,这就是为什么默认是 async。 比如可以把首页的登录弹窗留到点击登录才加载,不过这样 子容易有登录交互体验比较差,加载慢的问题,这就需要 prefetching 和 preloading 了,也就是等待页面基本加载完成 了,带宽空闲了,再偷偷加载这里的逻辑而非点击登录才下 载(其实还是要再下载,只不过下载过一次,有缓存了,非 常快)。 使用如下魔法注释即可实现;

7.CSS文件的代码分割

入口文件名会看 filename,而间接生成的文件名(就是在入 口文件中引入的文件)会看 ChunkFilename。 在默认情况下,我们打包并不会单独生成 CSS 文件,因为都 写在 js 中。 MiniCssExtractPlugin 插件(不支持 HMR,一般在线上使用) 可以对 CSS 进行代码分割然后单独生成 CSS 文件。 安装该插件,在配置文件引入插件,而且还需要更改之前处 理 CSS 的 loader(线上环境配置时)。

2345_image_file_copy_376.jpg

如此依然没有单独的 CSS,因为之前的 tree shaking 把 CSS 给 摇掉了,记得 sideEffect 整一下。 如果 CSS 文件直接被 html 引用就走 filename,如果被间接引

用才走 chunkFilename。 如果需要对 CSS 代码做压缩,还需要安装引入对应插件。

8.webpack与浏览器缓存

Performance:false 可以关闭有关性能问题的警告。 目前如果已经访问过有缓存的 JS 文件有所变动,普通刷新的 情况下还是读取原本缓存下的 JS 文件,因为文件名字没有变, 这就可以引入一个 contenthash 来解决缓存问题。

 老版本的webpack可能出现即使没有改变文件也会出现hash 不一样的情况,因为 webpack 对业务逻辑与类库做了关联处 理,叫 manifest,既存在于业务逻辑也存在于类库,而可能 打包后它变得不一样,这里就用 runtime 抽离这些 manifest, 不影响我们的内容。

9.shimming的作用

 实际上我们打包的内容还需要做不少兼容问题(变片),比 如 babel-profill 处理低版本浏览器的语法不存在问题。 Webpack 中引入的变量只能在当前模块使用,但是如果我想 在其它模块使用呢(就是当前模块没有引入),可以利用插 件。如下即代表如果我在一个模块使用了$就会自动引入 jquery 模块且命名为$(表面看起来就我当前模块没有引入变 量却可以使用变量,实际上已经偷偷的引入了)。

new webpack.ProvidePlugin({
$jquery'
}),

我们可以在这里定义非常多的在各地使用的变量;一个模块的 this 默认就是指向自身,如果一定要指向 window?可以安装 imports-loader(修改 webpack 默认行为, 也就是变片的一种)。

2345_image_file_copy_377.jpg

10.环境变量的使用方法

module.exports = (env) →>{
if(env && env.production){
return merge( commonConfig,prodConfig);}else i
return merge( commonConfig,devConfig);}

env 就是环境变量,在 scripts 命令中传递它对应的属性也就 代表开启什么模式,名字可以改。不过一般不会用这个,还是跟之前一样指定每个命令对应的 config 文件。

相关文章
|
26天前
|
JavaScript
vue中的插件概念是什么?新手小白如何在Vue中引入插件
【8月更文挑战第21天】vue中的插件概念是什么?新手小白如何在Vue中引入插件
31 1
|
30天前
|
前端开发 JavaScript API
|
22天前
|
JavaScript 前端开发 API
解锁前端开发新境界:Vue.js携手Webpack,打造高效构建流程,你的项目值得拥有!
【8月更文挑战第30天】随着前端技术的发展,模块化与组件化趋势愈发显著。Vue.js 以其简洁的 API 和灵活的组件系统,深受开发者喜爱;Webpack 则凭借强大的模块打包能力成为前端工程化的基石。两者结合,不仅简化了组件编写与引用,还通过模块热替换、代码分割等功能大幅提升开发效率。本文将通过具体示例,展示如何利用 Vue.js 和 Webpack 构建高效、有序的前端开发环境。从安装配置到实际应用,逐步解析这一组合的优势所在。
34 0
|
22天前
|
JavaScript 测试技术
在不同 webpack 版本的 Vue 项目中配置 Storybook
在不同 webpack 版本的 Vue 项目中配置 Storybook
|
1月前
|
JavaScript
VUE——filemanager-webpack-plugin报错TypeError: Cannot read property 'isFile' of undefined
VUE——filemanager-webpack-plugin报错TypeError: Cannot read property 'isFile' of undefined
30 0
|
2月前
|
JavaScript
Vue 开发中的一些问题简单记录,Cannot find module ‘webpack/lib/RuleSet‘
Vue 开发中的一些问题简单记录,Cannot find module ‘webpack/lib/RuleSet‘
98 1
|
2月前
|
JavaScript 前端开发 应用服务中间件
|
2月前
|
JavaScript
vue 配置【详解】 vue.config.js ( 含 webpack 配置 )
vue 配置【详解】 vue.config.js ( 含 webpack 配置 )
41 0
|
3天前
|
JavaScript
vue中watch的用法
vue中watch的用法
|
3天前
|
JavaScript 前端开发
vue动态添加style样式
vue动态添加style样式