# 01-Webpack的介绍与安装

# 介绍

Webpack 是一个前端资源打包工具,能将各种js文件、图片、css等打包到一起,这样可以减少浏览器请求次数

image-20210103074704595

举例:

Snipaste_2021-01-14_11-01-06

# 安装

  1. 先安装node.js(因为Webpack是基于Node.js环境的工具)

  2. 用npm对项目进行初始化

    1. 先创建一个空文件夹,取个名字(注意:不能用中文,因为webpack在打包时会报错)。用vscode打开该文件夹

    2. 打开终端

      Snipaste_2021-01-14_12-44-12
    3. 在命令行内输入下面代码

      npm init -y   //执行完这行代码后会生成一个package.json文件
      
  3. 安装webpack和webpack-cli(webpack-cli是什么?client 客户、终端。安装了webpack-cli之后,我们就可以在命令行内使用webpack了)

    npm i webpack@4 webpack-cli@3 -D
    // @xxx 表示安装的版本号
    // -D (请大家补充到这里)
    
  4. 检查是否安装成功

    npx webpack -v
    

# 02-利用webpack进行打包

# 第一步:准备代码

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>webpack</title>
</head>

<body>
    <div id="app">
        <h1 class="title"></h1>
    </div>
</body>

<script>
    const $ = function (selector) {
        return document.querySelector(selector)
    }
    $('#app h1').innerText = "Hello, Webpack";
</script>

</html>

分散为多个文件并使用ES6语法

Snipaste_2021-01-30_10-24-19

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>webpack</title>
</head>

<body>
    <div id="app">
        <h1 class="title"></h1>
    </div>
</body>
<script src="./index.js"></script>

</html>
// tool.js
const $ = function (selector) {
    return document.querySelector(selector)
}
module.exports = {
    $: $
}
// index.js
import {
    $
} from './js/tool.js';
$('#app h1').innerText = "Hello, Webpack";

再次打开页面后发现报错,原因是浏览器不支持ES6语法。

Snipaste_2021-01-30_13-18-19

# 第二步:执行命令进行打包

npx webpack

打包后发现多了一个文件夹dist,里面有一个main.js文件

Snipaste_2021-01-30_13-19-52

# 第三步:修改index.html

      <!-- index.html -->
      <!DOCTYPE html>
      <html lang="en">

      <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>webpack</title>
      </head>

      <body>
          <div id="app">
              <h1 class="title"></h1>
          </div>
      </body>
-      <script src="./index.js"></script>
      <!--因为打包完后会生成main.js,所以在这里我们要引入打包后的文件:main.js-->
+      <script src="../dist/main.js"></script>
      </html>

# 03-打包配置

# 零配置打包

之所以刚才我们只执行一行代码就可以完成打包,原因是webpack从v4.0.0开始,可以不用设置任何配置便可以进行打包

当我们执行npx webpack这个命令时,webpack会先到根目录下找 webpack.config.js 配置文件,如果有就执行该配置文件并进行打包。没有则执行webpack的默认配置,默认配置代码如下:

const {resolve} = require('path')
module.exports = {
  mode: 'production',
  entry: './src/index.js', 
  output: {  
    path: resolve('dist'), 
    filename: 'main.js'  
  }
}

# 自定义打包

  1. 设置配置文件:在项目的根目录下创建一个webpack.pro.config.js文件,这个文件的作用就是对webpack打包进行配置

    const {resolve} = require('path')   //这是nodejs提供的路径功能模块
    module.exports = {
      mode: 'production',  //打包模式,值有:"production"(默认值) | "development" | "none"(一般不用)
      //production: 生产模式,他会自动启用webpack内部的一些优化措施,例如:代码压缩,混淆...(好处:打包好的文件体积小;坏处:需要消耗较长的时间)
      //development: 开发模式,不会对代码进行压缩,混淆...(坏处:文件体积相对大点;好处:打包很快)
      
      
      entry: './src/index.js',  //入口,告诉webpack从哪个文件开始进行打包
      output: {    //出口,告诉webpack打包好的文件放到哪里以及文件名称
        path: resolve('dist'),   //路径,path必须是个绝对路径
        filename: 'main.js'    //打包好的文件名称
      }
    }
    
  2. 打包:在命令行输入下面代码回车

    npx webpack --config webpack.pro.config.js
    

# 04-基础使用总结

  1. ==webpack-cli是干嘛的?==
  2. ==npm i webpack@4 中@4是什么意思?== 版本 会安装第4个大版本下最新的版本
  3. ==npm i webpack@4 -D 中-D是什么意思?==(作业)
  4. 如何检查是否安装成功? npx webpack -v
  5. ==自定义打包中我们学了哪几个参数?分别代表什么意思?==(不需要记,只需要看到代码后知道它是什么意思就行)
  6. ==自定义打包的命令怎么写?==(不需要记,只需要看到代码后知道它是什么意思就行)

# 注意事项:

  • 每次改了源代码都需要重新打包一次!!!
  • ==路径不能出现中文!!!==

# 05-增强功能-SourceMap

添加了SourceMap之后就会多生成一个叫 ".map" 的文件,它的作用是将打包后的代码和源代码做了一个映射,当代码出错了,它会帮我们定位到源代码出错的位置上。

const {resolve} = require('path')
module.exports = {
      mode: 'production',
      entry: './src/index.js', 
      output: {  
        path: resolve('dist'), 
        filename: 'main.js'  
      },
+    devtool: "source-map",  
}

# 06-loader(css-loader)

# 引入:如何将css文件进行打包?

准备css文件并引入到index.js中:

Snipaste_2021-01-30_17-16-10
require('./css/index.css');

打包时报错:

Snipaste_2021-01-30_17-18-22

原因:webpack只能处理js和json文件,不能出来别的文件

解决办法:需要loader来帮忙

# loader是什么?

loader是webpack的加载器,是一个总名称。它可以把图片、css、less、sass、字体等转换成js文件,然后webpack就可以处理了

# css-loader

作用:把css文件转成成js文件然后再加载到webpack中

使用步骤:

  1. 安装

    npm i css-loader -D
    
  2. 配置

    const {resolve} = require('path')
    module.exports = {
      mode: 'production',
      entry:'./src/index.js',
      output:{
        path: resolve('dist'),
        filename:'main.js'
      },
    +  module:{      // 处理非js模块
    +    rules:[     // 规则
    +      {
    +        test: /\.css$/, 		// 正则测试
    +        use: [   	
    +           {
    +  							loader: 'css-loader'    // loader
    +           }   
    +        ] 
    +      }
    +    ]
    +  }
    }
    

注意:==只使用css-loader没有任何效果,原因是只处理的css文件,但处理好之后往哪里输出没有设置==

# 07-loader(style-loader、less-loader)

# style-loader

作用:将css代码写到html的style标签里

使用步骤:

  1. 安装

    npm i style-loader -D
    
  2. 配置

    module.exports = {
      module:{ 
        rules:[ 
          {
            test: /\.css$/, 	
            use: [
    +           {loader: 'style-loader'},
                {loader: 'css-loader'}   
             ] 	
          }
        ]
      }
    }
    

# less-loader

作用:将less转换成css

使用步骤:

  1. 安装

    npm i less less-loader -D  
    

    补充:这里不光要安装less-loader,还需要安装less。原因:less-loader只是把less文件转换成js模块,只有转换成js模块后才能进行下一步处理。less这个工具才是真正将less转换成css。为什么他俩要分开?因为less-loader是webpack自己的处理器,而less是公共的插件。市面上不光只有webpack,还有别的打包工具也需要less。

    Snipaste_2021-01-29_15-53-06
  2. 配置

    module.exports = {
      module: {
        rules: [
          {
    -        test: /\.css$/, 
    +        test: /\.less$/,    
             use: [
                {loader: 'style-loader'},
                {loader: 'css-loader'},
    +           {loader: 'less-loader'}
             ] 
          }
        ]
      }
    }
    

    链式配置:

   module.exports = {
  module: {
       rules: [
      {
            test: /\.less$/,
   +        use: ['style-loader','css-loader','less-loader']
         }
       ]
     }
   }

注意:

  • ==use数组中的loader顺序不能颠倒,执行顺序是 从下往上从右到左==
  1. 修改index.js中的代码

    -      require('./css/index.css');
    +      require('./css/index.less');
    

# 08-loader(postcss-loader、autoprefixer插件)

# postcss-loader

作用:

  • 把css代码解析成 js 可以操作的 抽象语法树结构(Abstract Syntax Tree,AST)
  • 调用插件来处理 AST 并得到结果(eg:添加css3样式前缀、压缩代码等)

使用步骤:

  1. 安装

    npm i postcss postcss-loader -D
    
  2. 配置

    module.exports = {
      module: {
        rules: [
          {
             test: /\.less$/,    
             use: [
                {loader: 'style-loader'},
                {
      							loader: 'css-loader',  
                    options: {    
                      modules: true,  
                   } 
                },
    +           {loader: 'postcss-loader'},
                {loader: 'less-loader'}
             ] 
          }
        ]
      }
    }
    

注意:postcss-loader只是把css代码解析成AST,所以没有任何效果

# autoprefixer(是插件,不是loader)

作用:添加css3样式前缀(eg:Chrome: -webkit-、IE: -ms-)

使用步骤:

  1. 安装

    npm i autoprefixer -D
    
  2. 配置

    module.exports = {
      module: {
        rules: [
          {
             test: /\.less$/,    
             use: [
                {loader: 'style-loader'},
                {
      							loader: 'css-loader',  
                    options: {    
                      modules: true,  
                   } 
                },
                {
                   loader: 'postcss-loader',
    +                  options: {
    +                    postcssOptions: {
    +                      plugins: [
    +                        require('autoprefixer')({
    +                          // 市场份额大于1%的浏览器的,最后两个版本
    +                          overrideBrowserslist: ['last 2 versions', '> 1%']
    +                        })
    +                     ],
    +                  },
    +               },
               },
                {loader: 'less-loader'}
             ] 
          }
        ]
      }
    }
    

# 另一种方式:

单独创建postcss的配置文件 postcss.config.js(名字不能错,而且要放在项目的根目录下,否则webpack找不到它)

const autoprefixer = require('autoprefixer')
module.exports = {
  plugins:[
    autoprefixer({
      // 市场份额大于1%的浏览器的,最后两个版本
      overrideBrowserslist:['last 2 versions','> 1%']
    })
  ]
}

webpack.pro.config.js配置文件变为:

module.exports = {
  module: {
    rules: [
      {
         test: /\.less$/,    
         use: [
            {loader: 'style-loader'},
            {
  							loader: 'css-loader',  
                options: {    
                  modules: true,  
               } 
            },
+           {loader: 'postcss-loader'},
            {loader: 'less-loader'}
         ] 
      }
    ]
  }
}

# 09-loader(postcss-preset-env插件)

# postcss-preset-env(是插件,不是loader)

作用:将最新的CSS语法转换为目标环境的浏览器能够理解的CSS语法,而且它包含autoprefixer这个插件

使用步骤:

  1. 安装依赖

    npm i postcss-preset-env -D
    
  2. 配置规则

    module.exports = {
      module: {
        rules: [
          {
             test: /\.less$/,    
             use: [
                {loader: 'style-loader'},
                {
      							loader: 'css-loader',  
                    options: {    
                      modules: true,  
                   } 
                },
                {
                   loader: 'postcss-loader',
                      options: {
                        postcssOptions: {
                          plugins: [
    +                        require('postcss-preset-env')({
    +                           stage: 2,
    +                           browsers: ['last 2 versions','> 1%'],
    +                        })
                         ],
                      },
                   },
                },
                {loader: 'less-loader'}
             ] 
          }
        ]
      }
    }
    

stage共分为5个阶段,分别是:

  • stage-0 非官方草案
  • stage-1 编辑草案或早期工作草案
  • stage-2 工作草案
  • stage-3 候选版本
  • stage-4 推荐标准

# 10-loader(file-loader、url-loader)

# file-loader

作用:处理字体(图标)等文件

使用步骤:

  1. 安装依赖

    npm i file-loader -D
    
  2. 配置规则

    module.exports = {
      module: {
        rules: [
    +      {
    +          test: /\.(woff2?|eot|ttf|svg)$/,
    +          use:{
    +            loader:'file-loader',
    +            options:{
    +              // [name] [ext]都是占位符,就是把原来的文件名原样输出
    +              name:'[name].[ext]',
    +              // 输出的目录
    +              outputPath: './fonts'
    +            }
    +          }
    +      }
        ]
      }
    }
    

其实本质就是把字体(图标)等文件复制到另一个文件夹里

# url-loader

作用:处理图片

使用步骤:

  1. 安装url-loader

    npm i url-loader -D
    
  2. 配置规则

    module.exports = {
      module: {
        rules: [
    +      {
    +        test: /\.(png|jpe?g|gif|svg)$/,
    +        use: {
    +          loader: 'url-loader',
    +          options:{
    +            // 小于8k的图片转为base64格式
    +            limit: 8192,
    +            // 大于8k的图片则输出到下面对应的目录里
    +            outputPath: './images'
    +          }
    +        }
    +      }
        ]
      }
    }
    

# ==base64编码的优缺点:==

  • 优点:减少请求次数

  • 缺点:会增大文件的体积,比原来大0.3倍

​ 所以推荐小图片转base64(一般为8K),大图片推荐使用拷贝

#11-loader(babel-loader)

# babel-loader

作用:将最新的JS语法(eg:ES6、ES7)转换为目标环境的浏览器能够理解的JS语法(eg:ES5)

使用步骤:

  1. 安装

    npm i babel-loader @babel/core @babel/preset-env -D
    
  2. 配置

    {
    	test:/\.js$/,
      // 排除node_modules目录
      exclude:/node_modules/,
    	use:[
       	{
          loader:'babel-loader',
          options:{
            presets:['@babel/preset-env']
          }
        }
      ]
    }
    

# 12-plugins(html-webpack-plugin、mini-css-extract-plugin、clean-webpack-plugin)

插件的作用:用来扩展 webpack 的功能,增强webpack的魔法能力

# html-webpack-plugin

作用:把我们自己写的.html文件复制到打包目录下,并且自动引入相关资源

使用步骤:

  1. 安装

    npm i html-webpack-plugin -D
    
  2. 配置

    +     const HtmlWebpackPlugin = require('html-webpack-plugin')
          module.exports = {
            module: {
              rules: []
            }+       plugins:[
    +           new HtmlWebpackPlugin({
    +              template: resolve('./src/index.html'),  // 以当前src目录下的index.html为模版
    +              filename: 'index.html' // 生成的文件名称
    +           })
    +         ]
          }
    

# mini-css-extract-plugin

作用:把css代码提取到一个单独的css文件中,而不是直接插入到html的style标签中

使用步骤:

  1. 安装

    npm i mini-css-extract-plugin -D
    
  2. 配置

    +      const MiniCssExtractPlugin = require('mini-css-extract-plugin')
           module.exports = {
             module: {
              rules: [
                {
                   test: /\.less$/,    
                   use: [
    -                {loader: 'style-loader'},
    +                {loader: MiniCssExtractPlugin.loader}
                      {
                          loader: 'css-loader',  
                          options: {    
                            modules: true,  
                         } 
                      },
                      {loader: 'postcss-loader'},
                      {loader: 'less-loader'}
                   ] 
                }
              ]
            },
           plugins:[
    +          new MiniCssExtractPlugin()
           ]
        }
    

# clean-webpack-plugin

作用:在生成打包文件之前,清空dist目录

使用步骤:

  1. 安装

    npm i clean-webpack-plugin -D
    
  2. 配置

    +         const { CleanWebpackPlugin } = require('clean-webpack-plugin')
              module.exports = {
                 plugins:[
    +              new CleanWebpackPlugin()
                 ]
              }
    

# 12-plugins(webpack-dev-server)

# webpack-dev-server

作用:实现实时打包预览效果

  1. 当我们修改了代码webpack会自动打包
  2. 打包完成后会自动刷新浏览器

原理:

==把dist目录打包到内存中(此时我们在磁盘上是看不到dist目录的),然后以dist目录为静态目录,启动本地服务器==

使用步骤:

  1. 安装
   npm i webpack-dev-server -D
  1. 先创建一个新的文件webpack.dev.config.js,然后将webpack.pro.config.js代码复制一份给它

  2. 修改webpack.dev.config.js的代码

            const {resolve} = require('path')
            module.exports = {
    -          mode: 'production',
    +          mode: 'development',
               entry: './src/index.js', 
               output: {  
                  path: resolve('dist'), 
                  filename: 'main.js'  
               },
               devtool: "source-map",  
    +          devServer: {
    +              host:'localhost',  // 主机
    +              contentBase: './dist',
    +              port: 9090,  // 启动服务的端口
    +              open: true,   // 自动打开浏览器
    +          }
            }
    
  3. ==在package.json的scripts中配置打包快捷命令==

    "scripts": {
    	"build": "webpack --config webpack.pro.config.js",  
      "dev": "webpack-dev-server --config webpack.dev.config.js" 
    }
    
  4. ==在命令行执行:==

    npm run build  // 打包上线
    或者
    npm run dev    // 开发阶段
    

# 13-最后补充与总结

# 工程化开发的优势:

image-20201123173806350

# 今天要掌握的东西

  1. 每一个loader和插件的作用(看到名字后知道这是干什么的就行)
  2. 看到最基本的一些配置知道是干什么用的(我画个图)
  3. 所有要注意的地方(高亮)
  4. 知道配置代码里的每一条语句是干什么用的(不强制要求)

# 安装所有npm包

npm i webpack@4 webpack-cli@3 style-loader css-loader less less-loader postcss postcss-loader autoprefixer postcss-preset-env file-loader url-loader babel-loader @babel/core @babel/preset-env mini-css-extract-plugin html-webpack-plugin clean-webpack-plugin webpack-dev-server -D

##webpack.dev.config.js

const {
    resolve
} = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {
    CleanWebpackPlugin
} = require('clean-webpack-plugin')
module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        path: resolve('dist'),
        filename: 'main.js'
    },
    devtool: "source-map",
    devServer: {
        host: 'localhost', // 主机
        contentBase: './dist',
        port: 9090, // 启动服务的端口
        open: true, // 自动打开浏览器
    },
    module: {
        rules: [{
                test: /\.less$/,
                use: [{
                        loader: MiniCssExtractPlugin.loader
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            modules: true,
                        }
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: [
                                    require('postcss-preset-env')({
                                        stage: 2,
                                        browsers: ['last 2 versions', '> 1%'],
                                    })
                                ],
                            },
                        },
                    },
                    {
                        loader: 'less-loader'
                    }
                ]
            },
            {
                test: /\.(woff2?|eot|ttf|svg)$/,
                use: {
                    loader: 'file-loader',
                    options: {
                        // [name] [ext]都是占位符,就是把原来的文件名原样输出
                        name: '[name].[ext]',
                        // 输出的目录
                        outputPath: './fonts'
                    }
                }
            },
            {
                test: /\.(png|jpe?g|gif|svg)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        // 小于8k的图片转为base64格式
                        limit: 8192,
                        // 大于8k的图片则输出到下面对应的目录里
                        outputPath: './images'
                    }
                }
            },
            {
                test: /\.js$/,
                // 排除node_modules目录
                exclude: /node_modules/,
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin(),
        new HtmlWebpackPlugin({
            template: resolve('./src/index.html'), // 以当前src目录下的index.html为模版
            filename: 'index.html' // 生成的文件名称
        }),
        new CleanWebpackPlugin()
    ]
}

# webpack.pro.config.js

const {
    resolve
} = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const {
    CleanWebpackPlugin
} = require('clean-webpack-plugin')
module.exports = {
    mode: 'production',
    entry: './src/index.js',
    output: {
        path: resolve('dist'),
        filename: 'main.js'
    },
    devtool: "source-map",
    module: {
        rules: [{
                test: /\.less$/,
                use: [{
                        loader: MiniCssExtractPlugin.loader
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            modules: true,
                        }
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: [
                                    require('postcss-preset-env')({
                                        stage: 2,
                                        browsers: ['last 2 versions', '> 1%'],
                                    })
                                ],
                            },
                        },
                    },
                    {
                        loader: 'less-loader'
                    }
                ]
            },
            {
                test: /\.(woff2?|eot|ttf|svg)$/,
                use: {
                    loader: 'file-loader',
                    options: {
                        // [name] [ext]都是占位符,就是把原来的文件名原样输出
                        name: '[name].[ext]',
                        // 输出的目录
                        outputPath: './fonts'
                    }
                }
            },
            {
                test: /\.(png|jpe?g|gif|svg)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        // 小于8k的图片转为base64格式
                        limit: 8192,
                        // 大于8k的图片则输出到下面对应的目录里
                        outputPath: './images'
                    }
                }
            },
            {
                test: /\.js$/,
                // 排除node_modules目录
                exclude: /node_modules/,
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin(),
        new HtmlWebpackPlugin({
            template: resolve('./src/index.html'), // 以当前src目录下的index.html为模版
            filename: 'index.html' // 生成的文件名称
        }),
        new CleanWebpackPlugin()
    ]
}