LOADING

webpack 5.68.0版本教程示例详解

目录
  • 起步
    • 1. 基本安装
    • 2. 配置出入口
  • plugin
    • 1. html-webpack-plugin
    • 2. progress-bar-webpack-plugin
  • loader
    • 1. css-loader与style-loader
    • 2. url-loader与file-loader
    • 3. sass-loader
    • 4. postcss-loader
    • 5. babel-loader
  • 搭建环境
    • 1. 开发环境与生产环境
    • 2. 配置别名
  • 代码分离
    • 1. webpack-bundle-analyzer
    • 2. splitChunks(分离chunks)
    • 3. 动态导入(按需加载chunks)
    • 4. mini-css-extract-plugin(分离css)
  • 缓存
    • 1. contenthash
  • 定义全局环境变量
    • 1. 定义编译时全局变量
    • 2. 定义编译后全局变量
  • 优化打包体积
    • 1. 开启gzip压缩
    • 2.css-minimizer-webpack-plugin
    • 3. externals
  • 配置Vue
    • 配置React

      起步

      版本:”webpack”: “^5.68.0”

      前言:一定要注意版本,webpack更新太快了。对于一个前端来说,面试的时候总是会被问到webpack相关问题,这里带大家搭建一个简易的Vue/React项目,对webpack有个初步了解,也会提一些面试被经常的问题。码字不易,点赞支持!!!

      提示:修改了配置文件,要查看效果时,需要重启项目

      GitHub地址:github.com/cwjbjy/webp…

      文章根据评论区提出的问题,做出了相应的更新,并且将webpack的版本升级到5.68.0

      1. 基本安装

      (1)创建webpack5文件夹,用vscode打开,通过终端运行:

      npm init -y
      npm install -g yarn //如果安装过yarn就不用运行了
      yarn add webpack webpack-cli -D
      

      (2)在webpack5目录下新建 src,dist 文件夹

      新建 src/main.js

      console.log('Interesting!')
      

      2. 配置出入口

      新建build/webpack.common.js

      (1)配置入口

      可配置多个入口。但开发中一般是react或vue,为单页面web应用(SPA),入口一个即可

      //webpack.common.js
      const path = require('path')
      module.exports = {
        entry: path.resolve(__dirname, "../src/main.js"),
      }
      

      (2)配置出口

      只能有一个出口,这里指定输出路径为’dist’

      //webpack.common.js
      module.exports = {
        output: {
          path:path.resolve(__dirname,'../dist'),
          filename: '[name].bundle.js',
          clean:true //每次构建清除dist包
        },
      }
      

      现在,我们具有了最低配置。在package.json中,我们创建一个运行webpack命令构建脚本

      "scripts": {
        "build":"webpack --config build/webpack.common.js",
      }
      

      现在可以运行它了:

      npm run build
      

      在dist文件夹下会生成main.bundle.js

      目录结构:

      webpack 5.68.0版本教程示例详解

      plugin

      插件(Plugins)是用来拓展Webpack功能的,包括:打包优化、资源管理、注入环境变量

      插件使用:只需要require()它,然后把它添加到plugins数组中

      1. html-webpack-plugin

      html-webpack-plugin将为你生成一个HTML5文件,在body中使用script标签引入你所有webpack生成的bundle

      (1)安装

      yarn add -D html-webpack-plugin
      

      (2)新建 public/index.html

      <!DOCTYPE html>
          <html lang="en">  
          <head>    
              <meta charset="UTF-8" />    
              <meta http-equiv="X-UA-Compatible" content="IE=edge" />    
              <meta name="viewport" content="width=device-width, initial-scale=1.0" />    
              <title>Document</title>  
          </head>  
          <body>    
              <div id="app"><div>123
              </div>
              </div>  
          </body>
          </html>
      

      (3)配置

      //webpack.common.js
      const HtmlWebpackPlugin = require('html-webpack-plugin')
      module.exports = {
        plugins: [
          new HtmlWebpackPlugin({
              template: path.resolve(__dirname, '../public/index.html'),
              filename: 'index.html', 
          }),
        ],
      }
      

      (4)运行

      npm run build
      

      可以看到dist下多了index.html文件,并且打包生成的main.bundle.js在index.html中通过script标签被引入

      2. progress-bar-webpack-plugin

      作用:增加编译进度条

      (1)安装:

      yarn add progress-bar-webpack-plugin -D
      

      (2)配置:

      //webpack.common.js
      const chalk = require("chalk");
      const ProgressBarPlugin = require("progress-bar-webpack-plugin");
      module.exports = {
        plugins: [
          // 进度条
          new ProgressBarPlugin({
            format: `  :msg [:bar] ${chalk.green.bold(":percent")} (:elapsed s)`,
          }),
        ],
      };
      

      loader

      loader 用于对模块的源代码进行转换

      loader都在module下的rules中配置

      loader配置项包括:

      • test 正则校验(必须)

      • loader 调用loader的名称 / use 链式调用loader (二选一)

      • include/exclude 手动添加必修处理的文件/文件夹或屏蔽不需要处理的文件/文件夹(可选)

      • options 为loaders提供额外的设置选项(可选)

      tip:use链式调用,都是从右向左解析,需注意调用loader的顺序。loader要记住,面试经常被问到有哪些loader以及其作用

      1. css-loader与style-loader

      作用:加载css

      css-loader:会对@import和url()进行处理

      style-loader:将CSS注入到JavaScript中,通过DOM操作控制css

      (1)安装

      yarn add css-loader style-loader -D
      

      (2)在webpack.common.js中进行配置

      module: {
          rules: [
            {
              test: /\.css$/,
              use: ["style-loader", "css-loader"], //从右向左解析
            },
          ],
        },
      

      (3)示例

      新建src/assets/styles/style.css

      body{
          background-color: aqua;
      }
      

      在main.js中引入

      import './assets/styles/style.css'
      

      重新编译 npm run build,在浏览器中打开 dist/index.html,可以看到css已生效

      2. url-loader与file-loader

      webpack5内置了资源模块(asset module),代替了file-loader和url-loader

      例:加载图片资源

      //在rules下增加
         {
          test: /\.(png|svg|jpg|jpeg|gif)$/i,
          type: "asset",
          generator: {
            filename: "static/img/[name].[hash:7][ext]",
          },
        },
      

      3. sass-loader

      (1)安装

      yarn add sass-loader node-sass -D 
      

      (2)修改原先的css规则,改为:

      {
          test: /\.(css|scss|sass)$/,    
          use: ['style-loader', 'css-loader', 'sass-loader'] //从右往左编译的
      },
      

      (3)新建src/assets/blue.scss文件

      $blue: blue;
      body{
          color: $blue;
      } 
      

      (4)在main.js中引入blue.scss

      import './assets/styles/blue.scss'
      

      重新编译,打开dist/index.html,可以看到页面中的123已变成蓝色

      4. postcss-loader

      作用:处理css的loader

      配合autoprefixer,增加厂商前缀(css增加浏览器内核前缀)

      tip:面试的时候被问到两次(关键词:postcss-loader,autoprefixer,browserslist)

      (1)安装:

      yarn add -D postcss-loader autoprefixer
      

      (2)修改原先的css规则:

      postcss-loader在css-loader和style-loader之前,在sass-loader或less-loader之后(从右往左解析)

            {        
              test: /\.(css|scss|sass)$/,        
              use: [          
                  "style-loader",         
                  "css-loader",          
              {           
                  loader: "postcss-loader",            
                  options: 
                  {              
                  postcssOptions: 
                  {               
                      plugins: ["autoprefixer"],            },           
                      },       
                      },         
                      "sass-loader",     
                      ],    
                  },
      

      (3)在package.json新增browserslist配置

      "browserslist": {
          "production": [
            ">0.2%",
            "not dead",
            "not op_mini all"
          ],
          "development": [
            "last 1 chrome version",
            "last 1 firefox version",
            "last 1 safari version"
          ]
        }
      

      在style.css中增加以下样式:

      /* style.css */
      body {
          background: #999;
      }
      #app div{
          width: 200px;
          margin-top: 50px;
          transform: rotate(45deg); /* 这个属性会产生浏览器内核前缀如 -webkit*/
      }
      

      重新编译,打开dist/index.html查看效果

      5. babel-loader

      作用:解析ES6,JSX

      (1)安装

      现在babel已到7的版本,使用@区分其他非官方包

      Babel其实是几个模块化的包:

      @babel/core:babel核心库

      babel-loader:webpack的babel插件,让我们可以在webpack中运行babel

      @babel/preset-env:将ES6转换为向后兼容的JavaScript

      @babel/plugin-transform-runtime:处理async,await、import()等语法关键字的帮助函数

      运行命令:

      yarn add @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime -D
      

      (2)配置

      //webpack.common.js
      //在rules下增加配置
      {
          test: /(\.jsx|\.js)$/,
          use: ["babel-loader"],
          exclude: /node_modules/,
      },
      

      (3)增加babel额外配置项

      根目录新建.babelrc

      {
        "presets": ["@babel/preset-env"],
        "plugins": ["@babel/plugin-transform-runtime"]
      }
      

      (4)注意点

      babel-loader 8.x 对应@babel/core(7.x)

      babel-loader 7.x 对应babel-core 6.x

      (5)测试

      public/index.html

      使用es6的箭头语法

          <button>按钮</button>    
          <script>      
              document.querySelector("button").onclick = () => {        
                  console.log("es6");      
                  
              };    
          </script>
      

      重新编译,打开dist/index.html。通过点击可以看到信息被打印出来,说明es6解析成功

      搭建环境

      1. 开发环境与生产环境

      build下新建webpack.dev.js,webpack.prod.js

      (1)安装webpack-dev-server

      yarn add webpack-dev-server -D 
      

      (2)安装webpack-merge

      yarn add -D webpack-merge
      

      (3)webpack.dev.js

      const { merge } = require("webpack-merge");
      const common = require("./webpack.common.js");
      const path = require("path");
      module.exports = merge(common, {
        mode: "development",
        devServer: {
          hot: true, //热更新
          open: true, //编译完自动打开浏览器
          compress: true, //开启gzip压缩
          port: 3000, //开启端口号
          //托管的静态资源文件
          //可通过数组的方式托管多个静态资源文件
          static: {
            directory: path.join(__dirname, "../public"),
          },
        },
      });
      

      (4)webpack.prod.js

      const { merge } = require("webpack-merge");
      const common = require("./webpack.common.js");
      module.exports = merge(common, {
        mode: "production",
      });
      

      (5)修改package.json

      "scripts": {
          "dev": "webpack serve --config build/webpack.dev.js",
          "build": "webpack --config build/webpack.prod.js",
          "test": "echo \"Error: no test specified\" && exit 1"
        },
      

      运行npm run dev查看效果,更改index.html内容,可以看到页面进行了热更新

      (6)提示

      在webpack:5.38.1版本中,如果使用postcss-loader,需配置browserslist,但是配置browserslist后会引起无法热更新的bug,所以还需增加 target:web(与devServer同级)

      在webpack:5.54.0版本中,5.38版本的BUG已修复,无需再配置target:web。但引发了一个新问题,就是在Chrome浏览器中,如果不打开F12,更改文件内容则热更新(按需更新),但是打开F12控制台后,更改内容会导致每次更新都会重新刷新页面。在火狐浏览器,不管有没有打开F12,每次更新都会重新刷新页面

      在webpack5.68.0版本中,上述问题已修复

      2. 配置别名

      resolve与entry同级:

      //webpack.common.js
        resolve: {
          extensions: [".js", ".jsx", ".json", ".vue"], //省略文件后缀
          alias: { //配置别名
            "@": path.resolve(__dirname, "../src"),
          },
        },
      

      代码分离

      1. webpack-bundle-analyzer

      它将bundle内容展示为一个便捷的、交互式、可缩放的树状图形式。方便我们更直观了解代码的分离

      (1)安装

      yarn add webpack-bundle-analyzer -D
      

      (2)配置

      //webpack.prod.js
      const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 
      plugins:[
          new BundleAnalyzerPlugin()
      ]
      

      (3)运行 npm run build ,编译结束新开一个页面,可以看到bundle之间的关系

      2. splitChunks(分离chunks)

      作用:拆分chunk

      //webpack.prod.js
        //与plugins同级
        optimization: {
          splitChunks: {
            chunks: "all",
            name: "vendor",
            cacheGroups: {
              "echarts.vendor": {
                name: "echarts.vendor",
                priority: 40,
                test: /[\\/]node_modules[\\/](echarts|zrender)[\\/]/,
                chunks: "all",
              },
              lodash: {
                name: "lodash",
                chunks: "async",
                test: /[\\/]node_modules[\\/]lodash[\\/]/,
                priority: 40,
              },
              "async-common": {
                chunks: "async",
                minChunks: 2,
                name: "async-commons",
                priority: 30,
              },
              commons: {
                name: "commons",
                chunks: "all",
                minChunks: 2,
                priority: 20,
              },
            },
          },
        },
      

      (1)chunks:all / async

      all:把动态和非动态模块同时进行优化打包,所有模块都扔到vendors.bundle.js里面

      async:把动态模块打包进vender,非动态模块保持原样(不优化)

      (2)cacheGroups(缓存组)

      cacheGroups的作用是将chunks按照cacheGroups中给定的条件分组输出

      (3)test

      正则匹配,[\\/] 来表示路径分隔符的原因,是为了适配window与Linux系统。可通过(antd|@ant-design)匹配多个文件夹,达到将特定几个文件放入一个chunk中

      (4)priority

      优先级,默认组的优先级为负,自定义组的默认值为0

      (5)非动态导入(直接通过import引入)

      安装echarts

      yarn add echarts -S
      

      新建src/echart.js

      import * as echarts from "echarts"
      var myChart = echarts.init(document.getElementById('main'));
      // 指定图表的配置项和数据
      var option = {
        title: {
          text: 'ECharts 入门示例'
        },
        tooltip: {},
        legend: {
          data: ['销量']
        },
        xAxis: {
          data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
        },
        yAxis: {},
        series: [
          {
            name: '销量',
            type: 'bar',
            data: [5, 20, 36, 10, 10, 20]
          }
        ]
      };
      // 使用刚指定的配置项和数据显示图表。
      myChart.setOption(option);
      

      在main.js中引入

      import './echart'
      

      修改public/index.html

       <div id="main" style="width: 600px; height: 400px"></div>
      

      运行npm run build,在dist下会发现新增了echarts.vendor.bundle.js。这就是通过splitChunks分离出来echarts包

      3. 动态导入(按需加载chunks)

      按需下载资源,如路由懒加载。可以提升首屏加载速度

      (1)安装lodash

      yarn add lodash -S
      

      (2)通过import()语法实现动态导入

      //在main.js添加
      function getComponent() {
        // Lodash, now imported by this script
        return import("lodash")
          .then(({ default: _ }) => {
            const element = document.createElement("div");
            element.innerHTML = _.join(["Hello", "webpack"], " ");
            return element;
          })
          .catch((error) => "An error occurred while loading the component");
      }
      const button = document.createElement("button");
      button.innerHTML = "Click me ";
      button.onclick = () => {
        getComponent().then((component) => {
          document.body.appendChild(component);
        });
      };
      document.body.appendChild(button);
      

      (3)在webpack.prod.js中cacheGroups下添加(在上面splitChunks中已经加过了)

      lodash: {
        name: "lodash",
        chunks: "async",
        test: /[\\/]node_modules[\\/]lodash[\\/]/,
        priority: 40,
      },
      

      运行npm run build,只有点击按钮,lodash.bundle.js包才会被加载

      4. mini-css-extract-plugin(分离css)

      (1)安装

      yarn add -D mini-css-extract-plugin
      

      (2)配置

      将webpack.common.js下面的代码剪贴到webpack.dev.js

      //webpack.dev.js
      //开发环境不需要样式分离
        module: {    rules: [      {        test: /\.(css|scss|sass)$/,        use: [          "style-loader",          "css-loader",          {            loader: "postcss-loader",            options: {              postcssOptions: {                plugins: ["autoprefixer"],              },            },          },          "sass-loader",        ],      },    ],  },
      

      修改webpack.prod.js

      //webpack.prod.js
      //生产环境进行样式分离
      const MiniCssExtractPlugin = require('mini-css-extract-plugin');
      module.exports={
          plugins: [  
               new MiniCssExtractPlugin({
                  filename: "static/css/[name].[contenthash:8].css",
                })
          ],
        module: {    rules: [      {        test: /\.(css|scss|sass)$/,        use: [          MiniCssExtractPlugin.loader,          "css-loader",          {            loader: "postcss-loader",            options: {              postcssOptions: {                plugins: ["autoprefixer"],              },            },          },          "sass-loader",        ],      },    ],  },}
      

      用MiniCssExtractPlugin.loader代替style-loader,配合MiniCssExtractPlugin使用。

      (3)拓展:在webpack:5.38.1中,MiniCssExtractPlugin.loader需额外指定publicPath,来引用css资源。因为css样式分离到static/css文件夹下,会多两个层级目录,会使css中的背景图片路径不对。

      在webpack:5.68.0中无需下面的配置了,路径问题已经帮我们解决了

      //不再需要进行配置
      {
              test: /\.(css|scss|sass)$/,
              use: [{
                  loader: MiniCssExtractPlugin.loader,
                  options: {
                      publicPath: '../../'
                  }
              }, 'css-loader', 'sass-loader']
          }
      

      缓存

      当把打包后dist目录部署到server上,浏览器就能够访问此server的网站及其资源。而获取资源是比较耗费时间的,这就是为什么浏览器使用一种名为缓存的技术。可以通过命中缓存,以降低网络流量,使网站加载速度更快,然后,如果我们在部署新版本时不更改资源的文件名,浏览器可能会认为它没有被更新,就会使用它的缓存版本。

      所以我们需要将变动后的资源文件更改文件名,没有变动的资源(node_modules中的第三方文件)不更改包名称

      1. contenthash

      [contenthash]将根据资源内容创建出唯一hash。当资源内容发生变化时,[contenthash]也会发生变化。

      //webpack.common.js
        output: {
          path: path.resolve(__dirname, "../dist"),
          filename: "[name].[contenthash:8].js",
          clean: true, //每次构建清除dist包
        }
      

      定义全局环境变量

      1. 定义编译时全局变量

      (1)安装:

      yarn add cross-env -D
      

      (2)配置:

      "scripts": {
          "dev": "cross-env NODE_ENV=development webpack serve --config build/webpack.dev.js",
          "build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.js",
          "test": "echo \"Error: no test specified\" &amp;&amp; exit 1"
        },
      //webpack.common.js
      console.log('process.env.NODE_ENV',process.env.NODE_ENV)
      

      2. 定义编译后全局变量

      通过DefinePlugin实现

      新建 config/dev.env.js

      module.exports = {
          NODE_ENV:'"development"',
      }
      //webpck.dev.js
      const env = require("../config/dev.env");
      const webpack =require("webpack")
      module.exports = merge(common,{
        plugins: [
          new webpack.DefinePlugin({
            "process.env": env,
          }),
        ],
      })
      //main.js
      console.log(process.env)
      

      优化打包体积

      1. 开启gzip压缩

      (1)安装:

      yarn add compression-webpack-plugin -D
      

      (2)配置:

      //webpack.prod.js
      const CompressionPlugin = require("compression-webpack-plugin");
      module.exports = {
        plugins: [new CompressionPlugin()],
      };
      

      2.css-minimizer-webpack-plugin

      优化和压缩CSS

      (1)安装:

      yarn add css-minimizer-webpack-plugin --save-dev
      

      (2)配置:

      //webpack.prod.js
      const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
      optimization: {
          minimizer: [`...`, new CssMinimizerPlugin()],
        },
      

      3. externals

      防止将外部资源包打包到自己的bundle中

      示例:从cdn引入jQuery,而不是把它打包

      (1)index.html

          <script      src="https://code.jquery.com/jquery-3.1.0.js"      integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="      crossorigin="anonymous"    ></script>
      

      (2)webpack.common.js

      module.exports = {
        //...
        externals: {
          jquery: 'jQuery',
        },
      };
      

      (3)这样就剥离了那些不需要改动的依赖模块

      import $ from 'jquery';
      

      配置Vue

      (1)安装:

      yarn add -D vue-template-compiler@2.6.14 vue-loader@15.9.8
      

      注意 vue和vue-template-compiler版本号一定要一样,如果要更新vue,vue-template-compiler也要进行相应的更新

      也要注意vue-loader的版本,这里使用vue2,安装15.9.8版本

      vue-loader,用于解析.vue文件

      vue-template-compiler,用于模板编译

      (2)配置:

      webpack.common.js

      const {VueLoaderPlugin} = require('vue-loader'); // vue加载器
      module.exports={
          module:{
              rules:[
                  {
                      test: /\.vue$/,
                      loader: 'vue-loader',
                      include: [path.resolve(__dirname, '../src')]
                  },
              ]
          },
          plugins:[
              new VueLoaderPlugin(),
          ]
      }
      

      vue-loader要放在匹配规则的第一个,否则会报错

      (3)配置externals

      // index.html

      <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js"></script>
      <script src="https://cdn.bootcdn.net/ajax/libs/vue-router/3.5.3/vue-router.min.js"></script>
      

      // webpack.common.js

      externals: {
          'vue': 'Vue',
          'vue-router':'VueRouter'
      }
      

      (4)使用

      新建src/App.vue

      <template>    
      <div class="app">        
      <router-link to="/">home</router-link>       
      <router-link to="/about">about</router-link>        
      <router-view/>   
      </div>
      </template>
      <script>export default {    name: "App"}</script>
      <style scoped>.app {    font-size: 14px;    color: aquamarine;}</style>
      

      新建src/views/about.vue

      <template>    
          <div>        about页面    </div>
      </template>
      

      新建src/views/home.vue

      <template>    
          <div>        Home页面    </div>
      </template>
      

      新建router/index.js

      Vue.use(VueRouter);const Home = () => import( /* webpackChunkName: "Home" */ '@/views/home.vue')const About = () => import( /* webpackChunkName: "About" */ '@/views/about.vue')const routes = [{    path: '/',    component: Home}, {    path: '/about',    component: About}]const router = new VueRouter({    routes})export default router
      

      修改main.js

      import App from './App.vue';
      import router from './router';
      Vue.config.productionTip = false;
      new Vue({
          router,
          render: (h) => h(App)
      }).$mount('#app');
      

      重启项目,查看运行效果

      配置React

      安装其他所必须的babel外,还需安装@babel/preset-react

      1. 安装 babel解析JSX

      yarn add -D @babel/preset-react
      

      2. 配置

      //webpack.common.js
        entry: {
          main:path.resolve(__dirname, "../src/main.js"), //vue入口
          index:path.resolve(__dirname, "../src/index.js") //react入口
        },
      //.babelrc
      {
        "presets": ["@babel/preset-env", "@babel/preset-react"],
        "plugins": ["@babel/plugin-transform-runtime"]
      }
      

      3. 安装react

      yarn add react react-dom -S
      

      4. 使用

      修改index.html,增加

      <div id="root"></div>
      

      新建src/hello.js

      import React, {Component} from 'react';
      let name = 'Alan';
      export default class Hello extends Component{
          render() {
              return (
                      {name}
              );
          }
      }
      

      新建src/index.js

      import React from 'react';
      import {render} from 'react-dom';
      import Hello from './hello'; // 可省略.js后缀名
      render(, document.getElementById('root'));
      

      重启项目,可看到运行结果

      以上就是webpack 5.68.0版本教程示例详解的详细内容,更多关于webpack 5.68.0版本教程的资料请关注其它相关文章!

      原文地址:https://juejin.cn/post/7014466035923288072原文链接:https://www.jb51.net/article/266897.htm
      本文来源 爱码网,其版权均为 原网址 所有 与本站无关,文章内容系作者个人观点,不代表 本站 对观点赞同或支持。如需转载,请注明文章来源。

      © 版权声明

      相关文章