一、初始化前置工作

  • 安装webpack、webpack-cli(可以本地安装,这样就不会破坏全局的webpack环境)
  • 初始化package.json

    1. npm init -y
  • 新建webpack.config.js ```javascript // webpack.config.js中导出一个对象 // 所有的配置都在这个对象中

module.export = {}

  1. <a name="mHwNC"></a>
  2. ## 二、配置主要的属性
  3. - entry(入口)
  4. ```javascript
  5. entry: '' // 字符串
  6. entry: [] // 数组
  7. entry: {} // 对象
  1. output: {
  2. path: path.join(__dirname, 'dist'),
  3. // name是entry名字,默认是main
  4. // hash是根据打包后的文件内容计算出来的一个hash值
  5. filename: '[name].[hash:8].js'
  6. }
  7. // hash默认是20位
  • output(出口)==》对象
  • module(解析文件规则,配置文件需要哪些loader解析)==》对象
  • plugins(插件,代码优化、代码分割、生成htm等等)==》 数组
  • devServe(开发服务器)==》 对象

chunk:代码块,一个chunk有多个模块组合而成,用于代码合并和分割

三、解析过程

webpack启动后会从 entry 里配置的 module 开始递归解析 entry 依赖的所有module。每找到一module,就会根据配置的loader去找出对应的转换规则,对module进行转换后,在解析出当前module依赖的module。这些模块会以entry为单位进行分组,一个entry和其所有依赖的module被分割到一个组,也就是一个chunk。最后webpack会把所有的chunk转换成文件输出,在整个流程中webpack会在恰当的市级执行plugin中定义的逻辑。
(一个entry和其依赖的文件 ==》chunk)

四、通过插件生成html

  1. npm install html-webpack-plgugin -D
  2. plugins: [
  3. new HtmlWebpackPlugin({
  4. template: './src/index.html', // 以该html文件为模板,生成文件
  5. filename: 'index.html' // 产生后的文件名
  6. })
  7. ]

五、解析css、less、scss

1、配置解析loader

  1. 配置loader可以有多种
  2. use loader use+loader
  3. 1、在webpackmodule种配置
  4. 2、在引入的代码中配置
  5. require('style-loader!css-loader!./index.css')

处理scss、less

  1. less-loader scss-loader node-sass

2、css代码提取到css文件中

  1. // 有时候我们希望把页面中的css文件单独拉出来保存进行加载
  2. extract-text-webpack-plugin
  3. const cssExtract = new ExtractTextWebpackPlugin('css/css.css')
  4. plugins: [cssExtract]
  5. {
  6. test: /\.css$/,
  7. loader: cssExtract.extract({
  8. use: ['css-loader']
  9. })
  10. }

3、处理css属性前缀

  1. npm i postcss-loader autoprefixer
  2. {
  3. test: /\.css$/,
  4. loader: ['css-loader', 'postcss-loader']
  5. }
  1. 新建postcss.config.js
  2. module.exports = {
  3. plugins: [require('autoprefixer')]
  4. }

压缩css

  1. {
  2. test: /\.css$/,
  3. loader: ['css-loader?minimize', 'postcss-loader']
  4. }

4、loader的执行顺序

默认是从右向左执行
也可以从下到上执行

六、解析es6

  1. babel-loader babel-core babel-preset-env babel-preset-stage-0
  2. {
  3. test: /\.js/,
  4. use: {
  5. loader: 'babel-loader',
  6. query: {
  7. presets: ['env', 'stage-0']
  8. }
  9. }
  10. }

babel靠的就是ast语法树
image.png
压缩js

  1. uglifyjs-webpack-plugin -D

七、解析图片、字体文件

  1. 1、通过js new Image()
  2. let src = require('./img/1.png')
  3. let img = new Image()
  4. img.src = src
  5. document.body.appendChild(img)
  6. rules: [{
  7. // file-loader 是解析图片地址,把图片从资源位置拷贝到目标位置
  8. test: /\.(png|jpg|gif|svg|bmp)/,
  9. use: 'file-loader'
  10. }]
  11. 2、在css中当成背景图引入
  12. 3、通过img标签引入
  13. 需要html-widthimg-loader -D

把图片打包到固定的文件夹目录下

  1. rules: [{
  2. // file-loader 是解析图片地址,把图片从资源位置拷贝到目标位置
  3. test: /\.(png|jpg|gif|svg|bmp)/,
  4. use: {
  5. loader: 'file-loader',
  6. // 指定拷贝文件的输出目录
  7. options: {
  8. outputPath: 'images/'
  9. }
  10. }
  11. }]

将比较小的图标打包成base64格式,嵌到页面中,这样就能减少一次资源请求了

  1. rules: [{
  2. // file-loader 是解析图片地址,把图片从资源位置拷贝到目标位置
  3. test: /\.(png|jpg|gif|svg|bmp)/,
  4. use: {
  5. loader: 'url-loader',
  6. // 指定拷贝文件的输出目录
  7. options: {
  8. limit: 9 * 1024, // 小于9kb一下的 就打包成base64
  9. outputPath: 'images/'
  10. }
  11. }
  12. }]

八、配置多页

  1. // 先找到每个入口(entry),然后从各个入口分别处罚,找到依赖的模块(module)
  2. // 然后生成一个chunk(代码块)(一个代码块包含很多模块)最后会把chunk写到文件系统中(assets)
  3. entry: {
  4. index: './src/index.js',
  5. base: './src/base.js'
  6. }
  7. plugins: [
  8. new HtmlWebpackPlugin({
  9. template: './src/index.html', // 以该html文件为模板,生成文件
  10. filename: 'index.html', // 产生后的文件名
  11. chunk: ['index']
  12. }),
  13. new HtmlWebpackPlugin({
  14. template: './src/index.html', // 以该html文件为模板,生成文件
  15. filename: 'base.html', // 产生后的文件名
  16. chunk: ['base']
  17. })
  18. ]
  19. // 如果页面过多,不可能一直写HtmlWebpackPlugin,可以写for循环

九、公共库的打包

  1. 当一个模块里使用到一个公共库的时候
  2. 1、在当前需要使用的文件中引入
  3. import $ from 'jquery'
  4. 缺点:每次都要重新引入
  5. 所以打包后的文件都很大,原因是把jq引入进去了

image.png

  1. 2
  2. entry: {
  3. vendor: 'jquery'
  4. }
  5. plugins: [
  6. new HtmlWebpackPlugin({
  7. template: './src/index.html', // 以该html文件为模板,生成文件
  8. filename: 'index.html', // 产生后的文件名
  9. chunk: ['index', 'vendor']
  10. }),
  11. new HtmlWebpackPlugin({
  12. template: './src/index.html', // 以该html文件为模板,生成文件
  13. filename: 'base.html', // 产生后的文件名
  14. chunk: ['base', 'vendor']
  15. })
  16. ]
  17. ------
  18. 这样还是不行,因为在自己的模块,拿不到其他模块的变量,所以,$变量还是拿不到
  19. -------------
  20. 引入方式:
  21. 1、插件方法
  22. 用来自动向模块内部注入变量
  23. new webpack.ProvidePlugin({
  24. $: 'jquery'
  25. })
  26. 2expose-loader
  27. index中引入
  28. // expose-loader?全局变量名!模块名
  29. // 它会先加载此模块,然后得到模块导出对象,并且挂载到window上,这样全局下就都能访问到了
  30. let $ = require('expose-loader?$!jquery')
  31. 3
  32. rules:[{
  33. test: require.resolve('jquery'),
  34. use: {
  35. loader: 'expose-loader',
  36. options: ''
  37. }
  38. }]

十、别名的配置

  1. reolsve: {
  2. alias: { // 别名
  3. "@": './src'
  4. },
  5. // 命中率高的往前写,命中率低的往后写
  6. extensions: ['', '.js', '.json'] // 配置扩展名(引入模块的时候,可以不加扩展名)
  7. }

十一、优化方案

1、缩小文件搜索范围

  1. // 当你引入一个模块的时候,要进行解析
  2. resolve: {
  3. // 当你需要指定node_modules之外的其他模块目录的话
  4. modules: [path.resolve(__dirname, 'node_modules')],
  5. alias: {
  6. // 当加载react模块的时候,
  7. react: path.resolve('./cjs/react.production.min.js')
  8. }
  9. }

image.png
image.png
image.png
npParse:不需要递归解析此模块

  1. // 如果打包的文件过大
  2. rules: [
  3. {
  4. test: /\.jsx?$/,
  5. use: [
  6. {
  7. loader: 'babel-loader'
  8. }
  9. ],
  10. // 只转换或者编译src目录下的文件
  11. include: path.resolve('./src'),
  12. // 排除node_modules
  13. exclude: /node_modules/
  14. }
  15. ]

2、DLL

.dll为后缀的文件称为动态链接库,在一个动态链接库中可以包含给其他模块调用的函数和数据。

  • 把基础模块独立处理打包到单独的动态链接库里
  • 当需要导入的模块在动态链接库里的时候,模块不能再次被打包,而是去动态链接库里获取dll-plugin

1、定义DLL

  • DllPlugin插件:用于打包一个个动态链接库
  • DllReferencePlugin:在配置文件中引入DllPlugin插件打包好的动态链接库

image.png
2、使用动态链接库文件
image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png

十二、webpack-dev-server

webpack-dev-server打包后的文件,放到了内存中,所以我们在本地文件夹中是看不到的

十三、npm 和 npx的区别

npx可以执行命令(.bin目录下的命令,npm无法执行)
npm只能执行脚本命令

十四、监控源文件的变化

  1. // 表示监控源文件的变化,当源文件发售改变后,则重新打包
  2. watch: true,
  3. watchOptions: {
  4. exclude/ignored: /node_modules/,
  5. poll: 1000, // 每秒中询问的次数
  6. aggregateTimeout: 500, //
  7. }

十五、文件拷贝

  1. copy-webpack-plugin

image.png

十六、服务器自动刷新

我们可以监听到本地源文件发生变化时,自动重新构建出可运行的代码后在重新刷新浏览器。

1、文件监听

  1. watch: true, // 只有在开启监听模式时,watchoptions才有意义
  2. watchOptions: {
  3. ignored: /node_modules/,
  4. aggregateTimeout: 300, // 监听到变化发生后等300ms再去执行动作,防止文件更新太快导出编译频率太高
  5. poll: 1000 // 通过不停的询问文件是否改变链判断文件是否发生变化,默认每秒询问1000次
  6. }

2、文件监听流程

  • webpack定时获取文件的更新时间,并跟上一次保存的时间进行对比,不一致就表示发生了变化,poll就用来配置每秒访问多少次
  • 当检测文件不再发生变化,会先换成起来,等待一段时间之后再通知监听者,这个等待时间超过aggregateTimeout配置
  • webpack只会监听entry依赖的文件
  • 我们需要尽可能减少需要监听的文件数量和检测频率,当然,频率的降低会导致灵敏度下降

image.png
image.png

十七、区分环境

image.png
image.png

  1. // 定义环境变量
  2. plugins: [
  3. new webpack.DefinePlugin({
  4. __development__: JSON.stringify(process.env.NODE_ENV)
  5. })
  6. ]

十八、CDN

image.png

十九、Tree Shaking

Tree Shaking 可以用来提出 js中用不上的死代码,他依赖静态的es6模块化语法,例如通过import 和 export导入导出。

二十、提取公共代码

image.png

  1. optimization: {
  2. splitChunks: {
  3. ca
  4. }
  5. }

image.png
image.png

二十一、开启Scope Hoisting

image.png
合并多个模块
image.png

二十二、代码分离

image.png

tapable:
webpack本质上是一种事件流的机制,它的工作原理就是将各个插件串联起来,而实现这一切的核心就是Tapable,webpack中最核心的负责编译的Compiler和负责创建bundles的Compilation都是Tapable的实例
image.pngimage.png

npx 可以直接运行node_modules/ .bin目录下面的命令
可以用个配置package.json中的”script”

hash:cd26f7869d1f60899e93 默认是20位,一般我们取前八位

如何避免hash不重复:

二十三、配置请求跨域

  1. devServer: {
  2. proxy: { // 重写的方法 把请求代理到express服务器上
  3. '/api': {
  4. target: 'http://localhost:3000',
  5. pathRewrite: {'/api', ''}
  6. }
  7. }
  8. }

前端自己模拟数据

  1. devServer: {
  2. before(app) {
  3. app.get('/user',(req, res) => {
  4. res.json({name: 'zhangsan'})
  5. })
  6. }
  7. }