相信每个前端同学一定都使用过webpack,作为一个划时代的构建工具,却有很多同学对他的认识还停留在怎么改个host的认知上。由于现代的脚手架极大地提高了项目搭建的效率,但是工具的便捷性,自动化和完善的配置,也让很多同学对wepback认识不深。这里我整理了几个经典的场景的webpack应用,希望对大家有帮助
一、webpack的几个核心参数
作为铺垫,首先我们先介绍以下webpack的几个核心基本配置参数,也许懂的都懂,但是这里还是作为回顾和复习进行简单说明
1 entry
接受一个对象或数组,通过该配置,我们可以设定一个或者多个入口
2 output
接受一个对象,可以设置打包输出文件的输出路径及输出文件名。如果是多个入口的情况 可以使用[name]、[hash]等作为动态参数 设定多个输出文件的命名规则
3 plugins
一个数组,可以加载多个插件作为文件处理的。常用的插件如:
uglify-webpack-plugin:压缩 javascript
clean-webpack-plugin: 删除dist目录的文件
copy-webpack-plugin 复制文件
ExtractTextPlugin:将打包中的css单独抽离出来
HtmlWebpackPlugin:webpack打包后自动生成html页面
HappyPack: 多核打包 加快打包速度
CommonsChunkPlugin/SplitChunksPlugin : 抽取公用模块
webpack.DllPlugin+webpack.DllReferencePlugin 用与多入口项目 可以把入口的共同依赖 单独打包
4.module
通过设置module.rule数组来配置loader。loader一般通过正则表达式处理指定的文件类型,常用loader有
babel-loader @babel/core @babel/preset-env:JS转ES5的全家桶,需要配套使用
css-loader:解析import进来的.css文件
style-loader:把经过处理的css以<style>标签插入html中
html-loader :解析.html文件,能够从中分析出引入的js/css/图片等数据
5.resolve
该参数设定关于路径解析的配置。常用的属性有
extensions:['.js', '.vue', '.json'],指我们在代码中import的路径可以不写后缀名,会在次数组中自动搜索预设好的后缀名
alias:{'@': resolve('src')}:路径别名,通过该设置 在代码里面些@ 就表示src目录
6.devtool
该参数有10+个枚举值,设置的是代码的sourcesouMap的打包方式。有的会把sourcesouMap打包到代码里,有个会另外存为一个.map文件,sourcesouMap的细致程度也有区分
以上就是我认为比较重要的几个核心参数,大概能了解其中的用处,在实际使用过程中可以参照文档更细致的了解其配置
二、webpack的场景应用
好了,相信上面入门的配置项大部分同学都懂,但是在实际应用过程中,因为大部分情况脚手架都帮我们做好了完善的配置,基本不需要做什么变动。但是在一些项目开发中,无法用脚手架搭建的情况就需要我们自己动手写配置。下面这里总结了几个经典的场景,看看webpack如何发挥作用
场景1:打包公用代码到第三方库
现在有两个入口JS,就叫A.js和B.js吧,内容都很简单,他们都需要引入一个第三方库 ,比如就是Jquery。那么A和B文件 的代码非常简单:
import $ from jquery
console.log($)
如果不做什么特别的设置,我们在入口entry设好A和B两个入口,然后在output设置好输出文件的名称路径等,那么我们得到了两个输出文件,两个文件插入到html中都是正常运行的,可以正确输出了引入的就可以了。那么下面就用webpack帮我们实现这个功能。本案例中webpack版本是4.3,webpack4对于抽离第三库的功能已经集成了该功能,我们只需要用到optimization.splitChunks属性即可,不需要额外安装插件。
optimization: {
splitChunks: { //分割代码块
cacheGroups: { //缓存组 缓存公共代码
commons: { //公共模块
name: "commons",
chunks: "initial", //入口处开始提取代码
minSize: 0, //代码最小多大,进行抽离
minChunks: 2, //代码复 2 次以上的抽离
}
}
}
}
通过以上这个设置,最终输出的文件讲会把公用库抽离作为我们设置的commons.js

场景2:指定不予打包的库
现在我写了一个好用的图片播放插件,具体的实现大家脑补即可,但是我的代码中也使用了jquery,代码中大量的地方使用了$()进行DOM的操作。这个插件我最终是需要作为一个npm包上传到npm社区上让大家使用的。同样不经过任何优化的话,那么我最终打包出来供大家使用的JS,都将会包含了jquery的代码,那么每个使用了我的插件的代码里 就这样多出了几百K的体积,这也不是我所希望的。这种情况下,我可以在使用说明里先给大家做一个声明,也就是这个插件将基于jquery编写,在引用该插件的时候 需要保证环境中有jquery,这样我就不需要把jquery打包到我的文件中,我的插件包可能只需要几kb即可。这个需求核心则是使用到了externals的配置,该配置可以声明指定库不会打包到代码中,而在使用的地方仅留下一个引用,这样只要插件运行环境中有这个库,那么就可以正常运行,并且插件本身不会打包这个库的代码
externals:{
jquery:'commonjs2 jquery'
}
这里需要再额外解释一下 上面这个设置中 有一个commonjs2的字符串配置。这个地方是用来声明该库以哪个规范的形式载入到我们的代码中。所谓的规范就是只是原生js的形式或者AMD、CMD还是commonJS的规范引用进来。这里不做过多的展开,实际最常用的 其实就两个 :原生及commonJS。原生就是我们在html中 通过cdn方式引入 可以在页面直接运行的。而commonJS规范则是我们node使用的,我们基本都用这个方式 通过import或者require语法引入第三方包。而上面的案例中 我们通过import $ from jquery 也就是使用了commonJS规范,所以在设置externals时候需要声明'commonjs2 jquery'
三、webpack应用的进阶案例
这次我们打算做一个完整一点的npm包了。为了大家便于理解,那么现在我们需要做一个山寨简化版Element组件库。说到这个UI库,相信每个同学都用过了把。Element里有几十个组件供我们使用。我们可以通过以下全局代码引入:
Import ElementUI form ‘Element’
Vue.use( ElementUI )
这样在整个项目需要用到的地方 直接使用组件标签插入到模板中即可。但是如果我们只需要用到其中一个或者几个组件,我们是可以通过局部引入的方式 仅使用部分组件:
Import { button,select }form ‘Element’
这样我们自己的代码 将只会包含以上2个引入的组件代码,其他几十个组件是不会打包到我们的代码中。下面我们就来实现这样一个需求:
- 项目结构
首先这是一个vue组件库,我们可以通过vuecil脚手架创建出项目,并且构建如下目录
dist ...
src index.js
packages
button / button.vue
select / select.vue
checkbox /checkbox.vue
这里的项目结构大家有一个直观认知即可
2.代码引用
这个项目的入口为src/index.js,该文件需要实现的是install方法,因为全局引入的时候 通过Vue.use(我们的组件库),就会调用install方法 这里我们需要将其实现,实现的功能就是通过遍历对象或者数组 吧packages里面的三个vue组件注册到Vue中
Import button from ‘packages/button’
Import select from ‘packages/select’
Import checkbox from ‘packages/ checkbox’
Const components = [button ,select,checkbox]
const install = function(Vue, opts = {}) {
components.forEach(component => {
Vue.component(component.name, component);
})
};
export default {
button ,
select,
checkbox,
install
}
而我们的三个组件则是正常的一个vue组件,这里应该不需要再给大家写伪代码了。
3.webpack配置
完成上述的基本结构下面就可以进行webpack打包配置了。首先entry肯定是我们的src/index.js 相信这里都不会有什么异议。然后重点是配置output:
output: {
path: path.resolve(process.cwd(), './lib'), //打包输出的路径
filename: 'comp.common.js',, //打包输出文件名
library: 'COMP', // 此项需要搭配libraryTarget使用,'commonjs2'时该项不生效
libraryTarget: 'commonjs2' // 声明输出文件支持的规范
},
因为我们的组件库的使用是通过import语句引入,那么libraryTarget需要设置为'commonjs2' ,跟案例二中的说法一样。libraryTarget有多个值,只有使用部分选项,才需要设置library,其他情况下 library可以不用写,写了也不会生效。如果现在输出的话,那么三个组件的代码都会被打包到comp.common.js中,那样就没有办法做局部引入了。所以这里又得用到externals这个外部扩展的配置了。
Externals{
‘./packages/button.vue’:’commonjs2 button’,
‘./packages/select.vue’:’commonjs2 select’,
‘./packages/checkbox.vue’:’commonjs2 checkbox’
}
这里可以打包一下,生成出来的comp.common.js 可以发现只留下了引用,而三个组件本身的代码 不会被打包进来。但是这样就大功告成了吗?并没有,因为外部扩展的这三个库 并不是公用的cdn库,而是存在于我们本地项目中,所以还需要对三个组件进行单独打包出一个可用的组件.js,这样才能正常使用。这个配置入口应该是三个,对应三个组件,输出的规范应该也是commonjs2,因为我们的src/index.js就是使用import引入了三个组件
打包单个组件.js
entry:{
"button": "./packages/button.vue",
"select": "./packages/select.vue",
"checkbox": "./packages/checkbox.vue"
},
output: {
path: path.resolve(process.cwd(), './lib'),
filename: '[name].js', // 通过[name]可以动态生成了button.js select.js
libraryTarget: 'commonjs2'
}
最后,我们的打包命令实际是需要运行2个webpack配置,得到的文件一个是四个:comp.common.js以及三个组件名.js。那么通过webpack的tree shaking的能力,当我们使用局部引入的写法,最后生成的打包文件将只打包局部使用到的组件代码了。
到此文本就结束了,希望对大家带来实际的经验帮助。下一期我们来聊聊webpack的运行原理,一起动手撸一个简易的webpack吧!
网友评论