webpack(4)说复杂也不复杂。不复杂,核心概念不外乎是entry, output, loader, plugins。webpack4还新增了optimization选项,用于代码分割和打包优化。现在webpack官网文档已经写的挺棒了。
然鹅,当你真正开始手写一个webpack.config.js的时候,你就会发现,要记得东西有点儿多,还挺复杂的……
好啦,Ladies and Gentleman,本文讲的是手动编写基于vue开发的webpack4配置,以下内容主要针对生产环境,开发环境的配置于之后奉上。 created by 2018.07.22 。
webpack的核心概念包含以下几个,要牢记:
- entry - webpack打包的入口,并非代码执行的入口;
- output - webpack打包后生成的静态资源文件,它是最终会被html引用的文件;
- loader - 对于非js的模块(或说文件),转化成webpack能够处理的js文件;对于还要进一步处理的js文件进行加工处理;
- plugins - 参与到整个webpack打包的过程(webpack打包的各个生命周期),可与loader结合使用,提供相应/辅助的功能。
Entry:
entry可以是单个入口,也可以是多入口。单个入口的写法:entry: 'a.js' 或 ['a.js', 'b.js']
多个入口的写法:
entry: { a: 'a.js', b: 'b.js'}
webpack会以你给的entry为入口,根据dependency graph,挨个打包,结合其他相应的设置,最终输出成页面要引用的静态资源文件。注意了,这里提到的“结合其他相应的设置”,很可能是不止一处的设置。???
output
output里面的选项主要有(但远不止以下):- filename: '[name].[hash].bundle.js' // [name]和entry里面的name对应
- path: path.resolve(__dirname, 'dist') // 指最终打包生成的目录
- publicPath: 可以是'./dist/' 或 '/' 或 cdn地址 // 指外部访问静态资源文件的路径
- chunkFilename: '[name].chunk.js' // 指用webpack.ensure或import().then()动态加载的文件
loader
loader就是把模块转换成webpack能够处理的js文件(如css,scss,vue等非js模块),或者对js模块本身进行再加工(如编译es6语法等)。loader的写法好有好几种,loader一般放在module这个对象里的rules里面,现总结以下4种:module: { rules: [ { //第一种, 需要用到的loader简单的放在use数组里 test: /\.(sa|sc|c)ss$/, use: [ devMode ? 'style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader', ], }, {// 第二种,use里面是一个个对象,这种方式可以给loader进行配置 test: /\.css$/, use: [ { loader: 'postcss-loader', options: { ident: 'postcss', plugins: [ require('autoprefixer')({ browsers: ['iOS >= 7', 'Android >= 4.1'] }), ] } } ] }, {//第三种,单个loader和对象loader一起放在use数组里 test: /\.(png|jpg|jpeg|gif)$/i use: [ 'file-loader', { loader: 'image-webpack-loader', optiosn: { pngquant: { quality: '65-80' } } } ] }, {//简单使用loader,不用use test: /\.vue$/, loader: 'vue-loader' } ]}总结一下loader的常用四种写法:use: [xxx, xxx]use: [{loader: XXX}, {loader: XXX}]use: [{ loader: XXX, options: {}}, 'XXX']loader: [XXX, XXX] 或 loader:XXX, options: {XXX}???
常用的loader有:
- 处理样式的:style-loader,css-loader,postcss-loader,sass-loader,less-loder
- 处理es6的:babel-loader(要连同babel-core, babel-preset-env)一起用
- 处理图片的:file-loader, url-loader, image-webpack-loader
Plugins
常用的plugin有:- 压缩js:uglifyjs-webpack-plugin
- 合并&压缩css: mini-css-extract-plugin,optimize-css-assets-webpack-plugin
- 清除目录:clean-webpack-plugin
- 生成html:html-webpack-plugin
- postcss相关的:postcss-plugin-px2rem,postcss-preset-env,postcss-sprites,autoprefixer
- webpack自带的方法:webpack.ProvidePlugin等
是不是开始觉得要记得东西很多啊?蛤蛤蛤蛤蛤蛤,不要急,要记得东西远不止这些……
以上讲的都是些概念和基本配置,结合起来怎么用呢?
先上目录:因为只写一个注册页,笔者没有用vue-cli,选择手动撸一个vue的webpack配置。
打包编译vue文件,需要用到vue-loader,样式需要用vue-style-loader,那么<template>怎么办呢?一定记住安装vue-template-compiler,虽然它只存在于你的node_modules文件夹中,但是vue-loader需要用到它,所以务必记住安装。
另外,在loader中设置了vue-loader之外,还得设置一个变量const { VueLoaderPlugin } = require('vue-loader'),并且在plugins里面创建一个它的实例才行,即new VueLoaderPlugin()。
ps. 系不系感觉复杂了?我也布吉岛为神马这些配置要分散在不同地方进行配置,这就加剧了webpack上手的难度。。。。
在我们书写配置的时候,一定要清楚自己想要webpack帮助你达到什么目的,以此来选择需要的loader和plugin以及其他辅助工具。
除了上面讲到的转化vue模块外,在生产环境下,我需要webpack帮助我的主要是打包、压缩js,css,images,自动生成html文件,以及每次打包前先删除已存在的dist目录。所以上图中所引入的模块就是能完成这些功能的基本工具。
另外webpack最显著的特点,这也是webpack创始人打造它的初衷,就是code splitting!既然如此,我们当然要发挥webpack这个特点,帮助我们优化!注意哦,代码分割是内置在webpack里面的方法。在webpack4中,它在optimization里面配置,也就是取代了之前的commonsChunkPlugin这个插件。如下:
另外,runtimeChunk用来单独打包压缩运行时的webpack代码。
至此,经过npm run build之后,代码执行的入口文件为以下四个:
再让我们来分析一下打包后的文件大小,总之我打包后vendor变得很大,即便uglify了,也有188k。这可不行!这时候请记住plugin: compression-webpack-plugin。
然后如下图在plugins里面创建一个它的实例:然后你再打开页面就会发现vendor.bundle.js变成了63.4k。虽然还没有达到我的要求,但是已经缩水一半以上了!
补充说一下webpack4“动态引入”的不同,如果要用import().then()这个动态引入方法,需要安装babel-plugin-dynamic-import-webpack这个插件才行。
总结一下webpack的复杂性,总体来讲就是要记得东西很多,有点“无厘头,没规律”,具体来说至少包含以下几个方面:
- 有些功能用loader就完事了,可有些还要配合着plugins去写。有些loader本身要配置plugins,有些loader需要到外面大plugins对象里进行设置。没有统一的规律遵循,比较杂乱;
- 不同loader和plugins配置项可以很多,不同版本也不一样(希望以后版本更迭的成本小一些,给开发者多一些温油);
- 像babel这样的,要注意不同版本的差别,否则会报错。babel-loader, babel-core, babel-preset, babel-polyfill一定要对应着来。并且用了babel-loader并不久完事了,要去设置对应的presets告诉babel要把你的es6编译成啥样的规范,可以写在options里,也可以在根目录设置.babelrc。另外要编译es方法和函数还要用到polyfill,如果是开发框架则要用另一个babel-plugin--transform-runtime --save-dev和babel-runtime --save。
总之要记的很多就是了。。。
但是呢,如果能记住这些杂碎的东西,webpack能帮助你做到很多事!也就觉得没那么复杂了。话虽如此,要弄懂原理是另一回事啦。???
good night~