学webpack基础用法 有这一篇就够了

921 阅读29分钟

webpack核心概念之entry

entry的含义

entry用来指定webpack的打包入口,那么为什么我们需要entry呢?这个离不开webpack
构建的机制,webpack与其他构建工具不同的是,webpack是模块打包器,在webpack里面
它会把一切资源,不管是js,css这些代码资源,还是非代码资源,比如像图片,字体,甚至
文本等,它都会把他们当成一个个的模块,对于所有模块之间它们会存在依赖关系的,因
此在webpack里面根据指定的entry的入口文件找到依赖,入口文件的依赖可能也会依赖其
他的文件,这样就会存在一棵依赖树,在这棵依赖树,这要遇到了依赖,webpack就会将依
赖文件加入到这个依赖图里面去,最终遍历完之后,才会生产打包之后的资源,如下图所示:

entry的用法

entry会有两种情况,一种是单入口的文件,另外一种是多入口的文件
单入口适用于:一个项目里面只有一个入口文件,就是只有一个页面,或者是一个单页应用
多入口:适合多页面场景也就是通常所说的多页应用
这里面对应的写法也是不同的,单入口 entry是需要写成字符串的形式,如果是多入口,entry是一个对象。

  1. 多个 entry 的时候,最基本的是输出的 js 数量和 entry 数量相同的,js 文件的名字通常是和 entry 的 key 名字一样。比如: entry: { index: './src/index/index.js', search: './src/searc/index.js' } 对应输出的 js 文件应该是 index.js 和 search.js。 当然了,如果你有做一些代码分割,那么生成的 js 文件会更多,不过页面的主 js 文件数量和 entry 数量是一致的。
  1. html 的数量和 entry 的数量也是一致的,如果也是1里面提到的 entry,那么将会生成: index.html 和 search.html。这个可以借助 html-webpack-plugin(github.com/jantimon/ht…) 达到效果

webpack核心概念之Output

output的概念

Output 用于指定打包的输出,也就是说entry对应的是源代码,Output对应转换后的结果代码,我们可以通过output来指定webpack 编译的文件输出到磁盘,具体目录,文件名称都可以用output来指定(⽤来告诉 webpack 如何将编译后的⽂件输出到磁盘)

Output的用法

单入口配置

Output对于单入口配置的这种场景,其实只需要指定,filename和path这两个参数就可以了

module.exports = {
entry: './path/to/my/entry/file.js'
output: {
    filename: 'bundle.js’,
    path: __dirname + '/dist'
}
};

多入口配置

其实我们前面有提到entry其实是有多入口的,对于Output而言,里面并没有多个入口的说法,不管是一个入口还是多个入口,在Output里面都有一个Output,这里面用到了占位符的一个概念,这里面的filname:'[name].js' , 这个[name]就是代表占位符的含义,name代表打包出来的文件的名称

接下来演示一下具体实用办法:

运行一下(删除之前打包的dist)

可以看到结果已经出来了

webpack核心概念之loaders

loaders的概念

loaders在webpack里面算是很重要的概念,其实我们都知道,webpack原生只支持,js和json,对于其他的css文件,less,还有写js语法糖JSX,vue等,webpack并不能了解,那么这些东西怎么解决呢,我们需要loaders来进行处理,loaders的作用就是将原生webpack不支持的类型,通过loaders进行支持,loaders支持完了之后,webpack在进行解析的时候,才能将它们加进依赖图里面去,loaders本身是一个函数,也就是它接收源代码,经过loaders这个函数转换之后会输出个结果出来,这个结果给下一步去使用

webpack 开箱即用只支持 JS 和 JSON 两种文件类型,通过 Loaders 去支持其它文 件类型并且把它们转化成有效的模块,并且可以添加到依赖图中。 本身是一个函数,接受源文件作为参数,返回转换的结果。

webpack里面,目前比较常用的loaders

  • babel-loader:作用是转换es6,es7等js一些新特性的语法

  • css-loader: 因为webpack它本身并不支持.css的文件,因此需要通过css-loader对css进行加载,每当在js代码通过import这种语法把css引入进来的时候,这时候,webpack通过css-loader去处理这个css文件,并解析它

  • less-loader: 将less转换成css

  • ts-loader:将typescript转换成javascript

  • file-loader: 对于图片,字体,还有一些富媒体的文件可以通过file-loader进行解析

  • raw-loader:另外,首屏的资源,需要内联的情况下,可以借助raw-loader,它的作用就是一个文件直接以字符串的形式进行倒入

  • thread-loader:我们知道,正常情况下,webpack打包是开一个进程的,thread-loader可以让webpack以多进程的形式进行打包js和css,这样的话,也会让打包的速度更快。

loaders的用法

我们都知道一个webpack配置里面,可能会存在多个loader,这些我们会放在根结点下面有个moudle对象,对像里面有个rules数组,我们就把需要用到的loader放到rules数组里面就好了。对于没个rules里面的元素,我们通过test去匹配规则,使用use代表当前要使用的loaders的名称。

webpack核心概念之Plugins

Plugins概念

前面我们知道了loaders的作用的是处理webpack不能解析的文件,通过loaders让webpack能识别它们。plugins的作用其实是增强webpack的功能,plugins通常是用于打包输出的js的文件的优化,资源的管理和环境遍量的注入。其实你可以把plugins理解为任何loaders没办法做的事情,都可以通过plugins来完成,比如我们构建之前需要手动的去删除dist目录,其实这个操作我们就可以用plugins来很灵活的去完成。这里面值的提的是plugins是作用于整个构建过程,也就是说从构建开始到构建结束,整个阶段都可以用这个plugins的

插件⽤于 bundle ⽂件(打包输出文件)的优化,资源管理和环境变量注⼊ 作⽤于整个构建过程

常见的plugins

  • CommonsChunkPlugin: 通常是用在多个页面打包的情况下,可以将公共的js模块(多个页面都用来的js文件)提取出独立的commen.js

  • CleanWebpackPlugin: 是用来清理构建目录

  • ExtractTextWebpackPlugin: 将css从输出文件(bundle)文件里提取成一个独立的css文件

  • CopyWebpackPlugin: 将文件或者文件夹拷贝到最后输出的构建的目录里面

  • HtmlWebpackPlugin: 这个是特别有用的,后面介绍多页面打包时候会用到这个插件,这个插件就会创建html文件,而不需要每次构建完成之后在dist目录下面手动去创建html文件

  • UglifyjsWebpackPlugin:是用来压缩js

  • ZipWebpackPlugin: 可以将打包出来的资源生成一个zip包

Plugins的用法

使用起来也是很简单的, 只需要在plugins这个数组里面把定义好的插件放进去就可以了,对于多个插件我们就放到这个数组里面去就可以了。

webpack核心概念之mode

mode的概念

mode是用来指定webpack当前打包的环境,里面有三种类型的值,分别是:production,development,none。mode是webpack4提出的新的概念,webpack4以前是没有这个概念的,设置mode有什么好处呢,就是通过设置mode来自动触发webpack里面内置的函数,比如设置development这时候webpack会默认开启在开发阶段的比较实用的一些参数。如果你设置production,那么它会默认开启在生产阶段的参数,和一些插件的功能。如果你设置none那么它就什么都不会帮你做。

Mode ⽤来指定当前的构建环境是:production、development 还是 none 设置 mode 可以使⽤ webpack 内置的函数,默认值为 production

Mode 的内置函数功能

  • development:这两个插件会在代码热更新阶段很实用,可以在控制台去打印出是哪儿个模块发生来热更新,这个模块的路径是什么样的。

  • production:开启这些插件webpack会默认帮你做一些代码的压缩,生产阶段js压缩,会默认识别package.json里面sideEffects的参数,代码是否存在副作用的参数,同时也会帮你处理一些其他的场景。

  • none: 不会开启任何优化选项。

解析ECMASCript 6和React JSX

解析 ES6

我们知道webpack原生是支持js的解析,单对于es6的语法,原生是没办法解析到的,尤其es6里面有各种特性,因此的话,我们是需要借助bable-loader的,bable-loader是怎么使用的呢,我们首先在rules里面去匹配js文件,然后use:'bable-loader',通过bable-loader对js进行解析

const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
},
 module: {
 rules: [
         {
             test: /\.js$/,
             use: 'babel-loader'
         }
    ]
 }
};

增加ES6的babel preset配置

bable-loader是依赖bable的,因此需要在项目里面去使用bable的配置文件,bable配置文件的名称是.babelrc

使⽤ babel-loader babel的配置⽂件是:.babelrc

{
    "presets": [
      "@babel/preset-env”
    ],
    "plugins": [
        "@babel/proposal-class-properties"
    ] 
}

这里面由于支持es6的配置,因此我们需要在.babelrc下增加babel的preset配置,如果你之前有了解过bable的话,你会发现,babel有两块比较重要的概念,一个是presets,一个是plugins,plugins可以理解成一个plugin对应一个功能,presets是一切bable plugins的集合。
我们要解析ES6,我们只需要安装@babel/preset-env 这个preset就可以了

代码命令演示

我们要解析es6,首先需要安装一下@babel/core 和 es6的preset也就是@babel/preset-env,另外的话我们还需要通过babel-loader去解析它们,因此我们还需要安装babel-loader

npm i @babel/core @babel/preset-env babel-loader -D

然后我们进入项目,创建一下.babelrc这个文件

然后在这个文件里面,我们增加这个presets,presets是个数组,我们加上es6相关的preset
也就是babel/preset-env

接下来我们就修改一下webpack配置文件,这里面我们增加loaders的配置,需要放在module:下的rules数组里面,只需要匹配.js文件,通过use来指定我们使用的babel-loader

下面看一下实际效果

还是一样先清理掉dist目录,然后运行一下 npm run build

解析React JSX语法

首先我们在前面的babel的配置文件基础之上,增加一下react的preset的配置

@babel/preset-env 用于解析 ES6、ES7等语法
@babel/preset-react 用于解析 React JSX

增加完之后就可以正常去解析,react相关的语法了。然后我们回到项目里面来,首先我们安装一下react。
npm i react react-dom -S
npm i @babel/preset-react -D

对于 react和 react-dom 应该是: npm i react react-dom -S
对于构建相关配置应该: npm i @babel/preset-react -D
package.json中dependencies和devDependencies的区别是:devDependencies用于本地环境开发时候,dependencies用户发布环境,也就是开发阶段的依赖最后是不对被打入包内。
通常框架、组件和 utils 等业务逻辑相关的包依赖放在dependencies里面,对于构建、ESlint、单元测试等相关依赖放在devDependencies中


修改一下search.js,增加一下react组件的使用,

删除dist文件,重新进行打包
打包之后我们在打包后的dist文件中加入html文件,引入打包后的search.js,看一下运行效果

可以看到结果出来了!

解析CSS、Less和Sass

解析css

在webpack里面,我们要想解析css文件,首先我们需要使用css-loader,css-loader它的作用是用来加载.css文件。它的加载,实际是在代码里面,比如,index.js里面引入到了一个css文件,那么这时候它会去加载.css文件,并且将它转化成commonjs对象,插入到js代码里面去,然后接下来还是需要通过style-loader,style-loader的一个作用就是,将样式通过style标签插入到head里面来,这样的话样式才能在代码中显示出来。

通过例子演示一下解析css

首先的话我们还是安装一下style-loader和css-loader

然后我们创建一个search.css,就是给前面的search组件增加一下样式。这里面我们在之前写的search.js里面返回的div中加入className,然后再引入search.css(将search.css中写入样式),接下来我们要在webpack.config.js文件中增加css的解析。打包之后在dist里面创建search.html文件,引入打包好的search.js,在浏览器运行看样式生效。

到这里演示完成

函数组合通常有两种方式,一种是从左到右(类似 unix 的 pipe),另外一种是从右到左(compose)。此处 webpack 选择的是 compose 方式,从右到左依次执行 loader,每个 loader 是一个函数。

  • style-loader: 向 DOM 插入 style 标签,并且将样式插入进去,这样网页才能解析到
  • css-loader: 可以让 webpack 解析 css(因为 webpack 原生只支持 js 和 json 的解析),并且将解析出来的 css 转换成一个对象,插入到 JS 里面去。
  • less-loader: 将 less 转换成 css

loader 的执行有严格的顺序。解析 less 为例子: 必须先将 less 转换成 css,然后在解析css 为 cjs 对象,最后再将 cjs 对象以 style 标签的方式插入到页面上。 因此执行顺序是: less-loader -> css-loader ->style-loader。 编写顺序搞好需要和执行顺序相反,因为 loader 采用的是 compose 的实现,不是 unix 的 pipe 实现。

css-loader转换成的common.js对象是指node内部的module构造函数实例化的对象

Node.js 内部的模块机制规范是基于 common.js。类似: module.exports = function () {}; css-loader 就是将 css 代码转换成这样的对象形式。

webpack解析less

要想解析less,只需要在webpack引用loader的时候,增加一个less-loader就可以来,less-loader的作用就是将less转换成css
下面演示一下less解析: 首先我们安装一下less,和less-loader,因为less-loader需要依赖less,所有less也要一起装的 npm i less less-loader -D

然后我们打开我们的项目,将之前创建的search.css改成search.less,同时把引用的位置也进行修改,然后在webpack.config.js里面加入对less的解析(less-loader)

然后利用npm run build运行一下同样和之前一样增加html引入看效果

解析图片和字体

解析图片

要想解析图片,这里面用到非常实用的loader,叫file-loader,我们通过file-loader,它可以去处理一些文件 这里面只需要匹配一些图片(png|svg|jpg|gif)等图片资源,然后使用file-loader就可以解析这个图片了


下面我们在项目中演示一下,首先安装file-loader,然后找个图片,放入到项目中,我们在src下创建个文件夹images来放这个图片

接下来我们在项目里面,实际的去用一下,这个图片。我们在search.js这个组件里面,来用这个logo

接下来在webpack配置文件中增加对图片资源的解析

运行一下

这里面我们看到一个很长的一串,是图片的一个hash,然后我们看一下构建出来的目录

然后我们在浏览器里面刷新一下search.html看一下效果

可以看到图片就已经解析出来了

解析字体

在解析图片和解析字体是一样的

下面我们操作一下项目,引入字体

刷新页面

然后我们在看一下,图片解析和字体解析,有没有其他的方式呢
前面我们通过file-loader去解析图片和字体,除此之外,我们还可以用url-loader来解析

使用url-loader

url-loader和file-loader功能上差不多,只不过url-loader相比file-loader之外呢还可以做小图片或者小字体,自动的去做base64的转换,url-loader内部也是用的file-loader,这里面我们做一下,小图片,小资源base64的转换

这里面我们看到,url-loader接收一个参数,这个参数,通过options给loader进行传参,传的这个参数limit是10240,limit的单位是字节,也就是对于小于10240字节(10k)的图片webpack打包的时候自动转化成base64,大于的话用file-loader。
首先我们修改一下webpack的引用,将之前的file-loader替换成url-loader

打包一下

我们发现这里面已经没有图片的hash了(直接转化成base64进入search.js)

webpack中的文件监听

webpack文件监听及其使用

文件监听的优势主要是前面可以看到,我们每次修改了代码之后都要手动的去运行一下构建命令(npm run build),其实这样是比较麻烦的,尤其是我们在开发的过程中,有的时候在编写完代码之后,想马上看到结果,但是每次需要手动去运行这个构建命令,比较浪费时间,不高效,因此在webpack中做一个文件的自动编译是很有必要的,文件监听的作用也就是说,在代码发生变化的时候,能自动构建文件,并且把它输出出来。在webpack中主要有两种方式开启监听

  • 启动webpack的时候,我们在webpack命令后面加个 --watch
  • 在配置 webpack.config.js 中设置 watch: true 这里面我们用第二种方式,我们在package.json里面的sript里面增加个watch命令,我们只需要在一开始编译的时候,运行npm run watch,后面,每当有文件变化,它会自动的监听文件变化,然后自动构建输出到dist,不过这种方式有个缺点,每次自动编译完成时候,需要开发者手动刷新浏览器。

然后我们修改一下项目,看看会不会自动构建。

然后刷新浏览器

新加的字出来了。说明已经自动构建了

文件监听的原理分析

这里面webpack会轮循的去判断,文件最后的编辑时间是否发生变化,一开始会有一个文件的修改时间, 这个时候呢它就会把这个时间存储起来,下一次再有修改的时候呢,它就会和上一次存的时间做比对,如果发现不一致的情况,那么这个时候它不会立刻去告诉监听者,而是先把文件的修改先缓存起来,等待一定时间,等待的时间段内呢,如果有其他的文件也发生变化,那么它就会把这些变化的文件列表一起去构建,一起把构建的结果生成到bundle.js(输出文件)里面,这里面的aggregateTimeout就是缓存的等待时间,轮训时间是用poll进行控制。这里面有个点,使用的时候我们可以把node_modules忽略掉(设置ignored)参数,如果把node_modules忽略掉,文件性能会有所提升。

轮询判断⽂件的最后编辑时间是否变化
某个⽂件发⽣了变化,并不会⽴刻告诉监听者,⽽是先缓存起来,等 aggregateTimeout
    module.export = {
        //默认 false,也就是不开启
        watch: true,
        //只有开启监听模式时,watchOptions才有意义
        wathcOptions: {
        //默认为空,不监听的文件或者文件夹,支持正则匹配
        ignored: /node_modules/,
        //监听到变化发生后会等300ms再去执行,默认300ms
        aggregateTimeout: 300,
        //判断文件是否发生变化是通过不停询问系统指定文件有没有变化实现的,poll默认是1000ms,也就是间隔每秒检查一次
        poll: 1000  // 每秒检查一次变动
        } 
    }

webpack轮询指定文件是会调用Node.js里面的文件读取API fs这个模块来判断文件内容是否变化

webpack中的热更新及原理分析

热更新:webpack-dev-server

前面讲的webpack监听的方式,它最大的问题就是每次构建完之后,需要手动刷新浏览器,在webpack中其实有更好的方式,我们可以借助webpack-dev-serve,每次代码如果有修改,让它自动去构建,构建完成之后,通过热更新的方式,让浏览器里面的内容自动的去变化,WDS通常是需要和HotModuleReplacementPlugin插件一起使用。它们两个结合之后可以开启热更新的功能,另外WDS有个比较大的优势,没有磁盘的IU,就是它输出的文件是放到内存里面,而不是像watch这种方式放到本地的磁盘文件中去,所以说它的构建速度会有更大的优势。

在package.json里面增加dev命令。使用WDS,也就是webpack-dev-server增加一个--open参数,--open参数就是每次构建完成之后自动去开启浏览器
我们现在演示的是webpack-dev-server,它是开发环境用的,生产环境不需要用,所以先将mode改成,development,接下来我们需要引入webpack自带的HotModuleReplacementPlugin插件。插件是webpack内置的,直接引用webpack就可以。然后将插件加入plugins里面,之后需要配置一下devServer。指定contentBase是代表webpack-dev-server服务的基础目录,我们设置成./dist,同时开启热更新,将 hot设置成true。

这样,我们npm run dev

此时我们改变search.js组件,保存看是否自动热更新。

发现变化,浏览器也是没有刷新的。热更新成功!!!

热更新原理分析

这里面首先我们要知道一些概念。

  • Webpack Compile: webpack的编辑器,这个编辑器的作用是将JS的代码编译成Bundle.js(Bundle.js就是最后的打包好的文件)
  • HMR Server: 将热更新的文件输出给 HMR Rumtime
  • Bundle server: 提供文件在浏览器的访问,比如编译好的Bundle.js你如果正常访问的话是以文件目录的方式访问,这个Bundle serve是可以让你通过服务器的方式访问。比如localhost:8080 你的Bundle.js 可以以这种方式进行访问
  • HMR Rumtime: 会在开发的打包阶段 被注⼊到浏览器端的Bundle.js里面,这样的话浏览器的Bundle.js就会和服务器建立一个连接,通常这个连接是一个websoket,然后就可以更新文件的变化,当它收到有一些文件更新的数据,一些回包就会自动更新文件。
  • bundle.js: 构建输出的⽂文件

热更新过程

热更新其实有两个过程看上面的图。

  • 第一个过程就是启动阶段,启动阶段是在文件系统里面。就是文件系统进行编译,将初始的代码经过webpack Compile进行一个打包,打包好了之后,就是把编译好的文件传输给Bundle Server服务器,Bundle server就可以run这个文件。以server的方式让浏览器能够访问到。这个是启动的阶段,也就是上图的1-2-A-B。
  • 对于文件的更新的情况下,如果本地开发的时候有文件发生了变化,这个时候的流程其实是一个文件系统的变化。变化好了之后这个代码还是会经过Webpack Compile进行编译。编译好了之后它会将代码发送给HMR Server,HMR Server就可以知道哪儿些模块(代码的模块)发生了改变。发生改变之后HMR Server就会通知HMR Rumtime,HMR Server是在服务端,HMR Rumtime是在客户端,这样就是HMR服务器端通知浏览器端,哪儿些文件发生了变化,通常是以json数据进行传输,传输到Rumtime之后呢就会更新代码,最终代码经过改变,并且不需要刷新浏览器,这个就是热更新的原理。

文件指纹策略:chunkhash、contenthash和hash

什么是文件指纹

我们访问网站时候可以留意一下,各大网站打包出来的文件一般都会有一个后缀,这个后缀就是我们所说的文件指纹。

这里面的js的文件资源是index_ 后面有个几位的字符,这几位字符其实就是我们所说的文件指纹。
文件指纹有什么好处呢,通常文件指纹是用来做一些版本的管理,也就是说我们每次一个项目要发布的时候,我们有些文件修改了,这时候只需要把修改的文件发布上去,没有修改的文件,其实并不需要修改文件指纹的。所以文件指纹通常用做版本管理。另外的话,我们设置文件指纹之后呢,对于没有修改的文件,其实它可以持续的用浏览器本地的缓存,这样的话可以加速我们页面的访问。

常见的文件指纹有哪儿几种

主要是有三种

  • Hash:Hash它是和整个项⽬目的构建相关,在Webpack里面,打包阶段有Compile,Compilation,Compile是webpack启动那一次,它会创建Compile对象,Compilation是每次只要有文件发生变化这个Compilation就会变化的。这要有文件变化,这个hash其实会受Compilation的影响,Compilation发生变化,Hash值也会发生变化。每一次只要有一个文件变化,比如两个页面,修改了A页面的js,打包之后B页面的js其实也会发生变化,这个是没有必要的,因为A页面变化并没有必要影响B页面变化,这里面就有了Chunkhash的概念(只要项目⽂文件有修改,整个项⽬构建的 hash 值就会更改)
  • Chunkhash:和 webpack 打包的 chunk 有关,chunk通常指的是模块,不同的 entry 会生成不同的 chunk(模块),对于不同的entry入口,我们只需要它们的chunk保持独立就可以了,这样我们使用Chunkhash,每个页面,有一个页面发生变化并不影响其他页面,因此的话,我们对于js文件的指纹,一般采用Chunkhash。(和 webpack 打包的 chunk 有关,不同的 entry 会⽣成不同的 chunkhash 值)
  • Contenthash:这样可以这么理解,某一个页面,它既有js资源,也有css资源,如果我们css资源也使用Chunkhash的话呢,这个时候会有个问题,我们修改了js, 它的css并没有变,由于css资源也使用Chunkhash,就会导致css内容没有变化,发布上去的文件发生变化,因此css是采用根据内容,文件指纹的生成,像css文件通常采用contentHash。(根据文件内容来定义 hash ,文件内容不不变,则 contenthash 不变)
    总结一下:

这几种Hash要怎么用

js文件指纹的设置

js使用chunkhash

这个其实可以看到对于js的话,其实只需要设置输出的output就可以了。设置输出的output的filename,对于js使用chunkhash

CSS 的文件指纹设置

css使用contenthash 如果我们使用style-loader,或者css-loader,那么css会由style-loader将css插入 到style里面并且放在head头部里面,这个时候其实并没有独立的css文件,因此我们通常会采用 MiniCssExtractPlugin,通过这个插件把style-loader里的css提取出来,提取成一个独立的文件,因此对于这个css文件指纹,我们也设置在MiniCssExtractPlugin里面,给他设置一个filename,并且使用contenthash。

图片,字体指纹的设置

这个时候其实我们是设置在file-loader或者url-loader里面,然后给它传递一个options参数,这里面其实我们使用的是hash,这里面的图片和字体的hash和前面js里面提到的hash其实是不太一样的,这里面的hash其实也是指文件内容的hash,它是采用md5生成的,通常我们将打包后的图片放到独立的img的文件夹里面,这里面我们采用hash占位符,hash占位符后面我们加个:8的话代表我们取hash串的前八位,md5的hash默认是有32位,这里面还有其他的占位符,比如[ext]代表资源的后缀名称

演示js,css,图片文件指纹的设置

这里面为了便于演示,我们创建一个生产环境的webpack的配置,因为webpack的chunkhash是没办法和热更新一起使用的,没办法和HotModuleReplacementPlugin插件一起使用,所以我们创建了一个新的webpack配置,我们把之前那个webpack.config.js改成webpack.dev.js这个代表开发阶段的webpack的配置,然后复制一份,改成webpack.prod.js代表生产环境的webpack配置,生产环境不需要代码的热更新,所以把热更新的这块去掉,然后把mode改成production。
这时候我们在修改一下package.json
指定一下,生产环境build是 webpack.prod.js,开发环境环境是使用webpack.dev.js

修改好了之后我们增加一下文件指纹,首先增加一下js的文件指纹,js的文件指纹是直接修改这个output的filename,从原来的这样子

变成这样子 加一个[chunkhash:8]我们设置一个8位的长度,为了便于区分,我们将文件名称,和文件中间加一个下划线。


接下来我们增加一个图片的文件指纹

打包看一下

这里面其实我们看到js和图片的文件指纹都出来了。
下面我们设置一下css的文件指纹。首先安装一下MiniCssExtractPlugin插件

接下来我们在wbpack.prod.js配置里面把这个插件加进去,引入,然后添加到plugins数组里面去,然后给它传递filename,然后把filename设置一个文件指纹,文件指纹我们采用的是contenthash(filename: '[name]_[contenthash:8].css'),然后接下来我们要把这个插件的loader也加进去,值得注意一点插件是把这个css提取成一个独立的文件,这个插件的loader没办法和style-loader一起使用的,因为它们之前功能是互斥的,style-loader是把样式插入到head里面,这个插件是把样式提取出来,它们之前是有一些冲突,所以说的话呢,如果说你想把css提取出一个独立的文件,我们其实是要把这个style-loader删掉,删掉之后再使用这个插件的loader就可以了。

重新运行一下npm run build

可以看到css文件指纹也已经出来了。

HTML 、CSS和JavaScript代码压缩

一般情况在开发好代码之后,正式发布上线,代码还是要经过压缩的,资源压缩完之后,所占的字节越小访问的速度越快。

js文件的压缩

在webpack4里面,webpack内置了uglifyjs-webpack-plugin这个插件,所以默认打包出来的js就已经压缩过了,我们不需要在做一些其他的操作,当然你也可以手动安装uglifyjs-webpack-plugin,然后给他设置一些额外的参数,比如你可以开启它的并行压缩,这里面通过parallel参数去控制的(www.webpackjs.com/plugins/ugl…)

CSS 文件的压缩

我们知道在webpack3的时候,我们可以通过css-loader去设置一个minify参数来压缩css,但是在1.0版本之后去掉了这个参数,所以现在的话做css压缩我们是没办法用css-loader设置参数的方式压缩,这里面的话我们需要用到optimize-css-assets-webpack-plugin这个插件,使用这个插件的同时我们还需要安装一下预处理器,cssnano 这个css的处理器。然后我们匹配到所有的css文件,在用css的这个处理器再进行压缩。

html文件的压缩

利用html-webpack-plugin插件,要想压缩html,给这个插件设置压缩参数就可以了,这个插件的自身,可以传入一个minify这个参数,这些参数我们可以把,比如空隔,换行符号,包括一些注释,可以把它们全部都处理掉,从而来达到一个压缩效果。

演示一下具体压缩

首先我们来看一下css的压缩。这里面的话我们先安装一下这个optimize-css-assets-webpack-plugin插件

然后我们在生产环境的webpack配置文件引用一下这个插件,然后我们把插件加入到plugins数组里面来, 由于这个插件是依赖这个cssnano的css处理器,所以我们也需要安装一下。

接下来我们来看一下效果。

我们可以看一下,这个时候css已经压缩成功。 我们看一下打包后的js文件。

由于webpack4在mode设置成production的时候,默认开启uglifyjs-webpack-plugin这个js压缩插件,所以js是不需要额外处理已经压缩好了。
接下来我们看一下html的压缩。首先我们在src目录下新建两个空的html模版

首先安装html-webpack-plugin

接下来我们就引入html-webpack-plugin,然后将插件加入进plugins。这个插件具体的参数配置。

  • template:html-webpack-plugin插件的模版所在位置。
  • filename:指定打包出来的html的文件名称。
  • chunks:生产的html使用那儿些chunk(模块)。
  • inject:设置为true,那么打包出来的chunk(js,css)会自动注入到这个html里面来 通常情况下,一个页面需要对应一个html-webpack-plugin,这里面有两个页面,所以得引入两个html-webpack-plugin

如果看效果的话,我们把src下的search.js加一个id='root'的结点,这样压缩后引入的js可以直接将div插入到里面。
npm run build 打包

我们可以看到html已经压缩了,直接用浏览器打开这个压缩页面看一下效果

已经看到效果啦!!! 基础就完事了,后期会更新进阶用法。