webpack简介

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

核心概念:入口,出口,loader,插件

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
   plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

babel plugin preset区别

Babel是代码转换器,比如将ES6转成ES5,或者将JSX转成JS等。借助Babel,开发者可以提前用上新的JS特性,这对生产力的提升大有帮助。

实现Babel代码转换功能的核心,就是Babel插件(plugin)。

Babel插件一般尽可能拆成小的力度,开发者可以按需引进。比如对ES6转ES5的功能,Babel官方拆成了20+个插件。

这样的好处显而易见,既提高了性能,也提高了扩展性。比如开发者想要体验ES6的箭头函数特性,那他只需要引入transform-es2015-arrow-functions插件就可以,而不是加载ES6全家桶。

但很多时候,逐个插件引入的效率比较低下。比如在项目开发中,开发者想要将所有ES6的代码转成ES5,插件逐个引入的方式令人抓狂,不单费力,而且容易出错。

这个时候,可以采用Babel Preset。

可以简单的把Babel Preset视为Babel Plugin的集合。比如babel-preset-es2015就包含了所有跟ES6转换有关的插件。

webpack常用插件

loader用于打包文件,plugins 用于解决一些其他任务,比如去注释等等。

  1. HTML文件生成插件:html-webpack-plugin

产生背景:多入口时,当你的 index.html 引入多个js,如果这些生成的js名称构成有 [hash] ,那么每次打包后的文件名都是变化的。

作用:HtmlWebpackPlugin 在此可以用于自动重新生成一个index.html或依据模板生成,帮你把所有生产的js文件引入到html中,最终生成到output目录。

安装:

npm install --save-dev html-webpack-plugin
1

配置:

const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
    new HtmlWebpackPlugin()
]
1
2
3
4
  1. 图片压缩插件:imagemin-webpack-plugin

产生背景:图片过大,加载速度慢,浪费存储空间。

作用:批量压缩图片。

安装:

npm install --save-dev imagemin-webpack-plugin
1

配置:

//引入插件
var ImageminPlugin = require('imagemin-webpack-plugin').default;

//配置
plugins: [
    new ImageminPlugin({
      disable: process.env.NODE_ENV !== 'production', // 开发时不启用
      pngquant: {//图片质量
        quality: '95-100'
      }
    })
]
1
2
3
4
5
6
7
8
9
10
11
12
  1. css提取插件:clean-webpack-plugin (生产模式)

产生背景:在进行打包时,css代码会打包到JS中,不利于文件缓存。

作用:依据每个entry生成单个css文件(将css从js中提取出来)。

安装:

npm install --save-dev mini-css-extract-plugin
1

配置:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
plugins: [
  new MiniCssExtractPlugin(),
]
1
2
3
4

注意:不要在开发模式使用,因为不支持热加载

如果单入口,不需要这个

  1. css 去除无用的样式

产生背景:编写的css可能出现冗余情况。

作用:去除冗余的css代码。

安装:

npm install --save-dev purifycss-webpack
1

配置:

const purifycssWebpack = require('purifycss-webpack');
const glob = require('glob');

// Make sure this is after ExtractTextPlugin!
new purifycssWebpack({
  paths: glob.sync(path.resolve('./src/*.html'))
}),
1
2
3
4
5
6
7

注意:html文件生成 > css提取 > css摇树 参考文档

content-hash和hash区别

hash:跟整个项目的构建相关,构建生成的文件hash值都是一样的,只要项目里有文件更改,整个项目构建的hash值都会更改。 chunkhash:根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的hash值。 contenthash:由文件内容产生的hash值,内容不同产生的contenthash值也不一样。

显然,我们是不会使用第一种的。改了一个文件,打包之后,其他文件的hash都变了,缓存自然都失效了。这不是我们想要的。 那chunkhash和contenthash的主要应用场景是什么呢?在实际在项目中,我们一般会把项目中的css都抽离出对应的css文件来加以引用。如果我们使用chunkhash,当我们改了css代码之后,会发现css文件hash值改变的同时,js文件的hash值也会改变。这时候,contenthash就派上用场了。

参考文档 更详细文档

HMR(Hot Module Replacement)热更新原理

HMR是指当你对代码修改并保存后,webpack将会对代码进行重新打包,并将改动的模块发送到浏览器端,浏览器用新的模块替换掉旧的模块,去实现局部更新页面而非整体刷新页面。

Server端使用webpack-dev-server去启动本地服务,内部实现主要使用了webpack、express、websocket。

  • 使用express启动本地服务,当浏览器访问资源时对此做响应。

  • 服务端和客户端使用websocket实现长连接

  • webpack监听源文件的变化,即当开发者保存文件时触发webpack的重新编译。

    • 每次编译都会生成hash值、已改动模块的json文件、已改动模块代码的js文件
    • 编译完成后通过socket向客户端推送当前编译的hash戳
  • 客户端的websocket监听到有文件改动推送过来的hash戳,会和上一次对比

    • 一致则走缓存
    • 不一致则通过ajax和jsonp向服务端获取最新资源
  • 使用内存文件系统去替换有修改的内容实现局部刷新

参考文档