乐趣区

关于前端:Webpack-体系基础

为什么要学习 Webpack

  • 了解前端“工程化”概念、工具、指标
  • 进步集体外围竞争力
  • 成为高阶前端工程师的必经之路

什么是 Webpack

  • 前端我的项目由什么形成?—— 资源

    • 前端工程化工具呈现之前靠手动治理资源文件,比方通过 <link > 标签引入款式文件,通过 <script> </script> 标签引入 JS 文件等,但这种做法会呈现很多问题:

      • 操作过程繁琐
      • 存在依赖关系时要严格依照程序书写
      • 开发与生产环境统一导致难以接入 TS 或者 JS 的新个性
      • 比拟难接入 Less、Sass 等工具
      • JS、CSS、图片资源管理模型不统一等
    • 为了解决这些问题呈现了许多前端工程化工具:Webpack、Vite、browserifyjs 等,某种程度上正是这些工具的呈现,才有了前端工程这一概念
  • Webpack 实质上是一种前端资源编译、打包工具

    • 多份资源文件打包成一个 Bundle
    • 反对 Babel、Eslint、TS、CoffeScript、Less、Sass
    • 反对模块化解决 css、图片等资源
    • 反对 HMR + 开发服务器
    • 反对继续监听、继续构建
    • 反对代码拆散
    • 反对 Tree-shaking
    • 反对 Sourcemap 等

Webpack 的用法

  • 装置 Webpack:npm i -D webpack webpack-cli
  • 编辑配置文件 webpack.config.js

    // webpack.config.js
    module.exports = {
        entry: './src/index.js',
        output: {filename: "[name].js",
            path: path.join(__dirname,"./dist"),
        },
        module: {
           rules: [{
               test: /\.less$/i,
               use: ['style-loader','css-loader','less-loader']
           }], 
        }
    }
  • 执行编译命令:npx webpack会在根目录的 dist 文件夹下失去编译出的打包文件 main.js(默认为 main.js,能够批改)
  • 外围流程(极度简化版):入口解决、依赖解析、资源解析、资源合并打包
  • Webpack 实质上实现的事件:模块化 + 一致性

    • 多个文件资源合并成一个,缩小 HTTP 申请数
    • 反对模块化开发
    • 反对 typescript、CoffeeScript 语言
    • 对立图片、CSS、字体等其余资源的解决模型

应用 Webpack

  • 对于 Webpack 的应用办法,根本都围绕“配置”开展,可划分为两大类:

    • 流程类:作用于流程中的某个或若干个环节,间接影响打包成果的配置项
    • 工具类:主流程之外,提供更多工程化能力的配置项
    • Webpack 中的属性按应用频率来看:

      • entry / output
      • module / plugins
      • mode
      • watch / devServer / devtool

解决 CSS:例如在 JS 中引入 CSS 文件 import './index.css'

  • 装置 Webpack:npm i -D webpack webpack-cli
  • 装置依赖:须要应用的 loader:npm i -D style-loader css-loader
  • 编辑配置文件 webpack.config.js 增加 module 解决 CSS 文件

    const path = require('path');
    
    module.exports = {
        entry: './src/index.js',
        output: {filename: "[name].js",
            path: path.join(__dirname, "./dist"),
        },
        module: {
            rules: [{
                // test: /\.less$/i,
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }],
        },
        mode: 'development',
    }
  • 终端应用 npx webpack 进行编译

应用 Webpack 解决 JavaScript:接入 Babel 将高版本 JS 代码转译成低版本 JS 代码

  • 装置依赖:npm i -D @babel/core @babel/preset-env babel-loader
  • 编辑配置文件 webpack.config.js

    const path = require('path');
    
    module.exports = {
        entry: './src/index.js',
        output: {filename: "[name].js",
            path: path.join(__dirname, "./dist"),
        },
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
                {
                    test: /\.js$/,
                    use: [{
                        loader: 'babel-loader',
                        options: {
                            presets: [['@babel/preset-env']
                            ],
                        },
                    }],
                },
            ],
        },
        mode: 'development',
    }
  • 终端应用 npx webpack 进行编译

应用 Webpack 解决 HTML:不应用 loader 而是应用 HTML 插件

  • 装置依赖 npm i -D html-webpack-plugin
  • 编辑配置文件 webpack.config.js

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        entry: './src/index.js',
        output: {filename: "[name].js",
            path: path.join(__dirname, "./dist"),
        },
        module: {
            rules: [
                {
                    // test: /\.less$/i,
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
                {
                    test: /\.js$/,
                    use: [{
                        loader: 'babel-loader',
                        options: {
                            presets: [['@babel/preset-env']
                            ],
                        },
                    }],
                },
            ],
        },
        plugins: [new HtmlWebpackPlugin],
        mode: 'development',
    }
  • 终端应用 npx webpack 进行编译

应用 Webpack 进行热模块更新(HMR,Hot Module Replacement)

  • 写的代码可能立即更新到浏览器中,并且不必刷新浏览器
  • 编辑配置文件 webpack.config.js 增加 devServer 属性

    module.exports = {
        //...
        devServer: {hot: true,},
    }
  • 启动 Webpack 应用 npx webpack serve 命令

应用 Webpack 进行 Tree-Shaking,用于删除 dead code

  • dead code:代码没有被用到或者不可达到、代码的执行后果不会被用到、代码只读不写 …
  • 开启 Tree-Shaking:

    • mode: "production"
    • optimization: {usedExports: true}

      module.exports = {
          //...
          mode: "production",
          optimization: {usedExports: true,},
      }
    • 终端应用 npx webpack 进行编译

Loader 组件

  • Loader 的作用是进行资源内容的转化,Webpack 只意识 JS,Loader 用于解决非标准 JS 资源,翻译为规范 JS
  • 应用 Loader(以解决 less 文件为例):

    • 装置 Loader:npm i -D css-loader style-loader less-loader
    • 增加 module 解决 css 文件,其中 less-loader 实现了 less -> css 的转换;css-loader 将 CSS 包装成相似 module.exports = “${css}” 的内容,包装后的内容合乎 JavaScript 语法;style-loader 将 CSS 模块包进 require 语句,并在运行时调用 injectStyle 等函数将内容注入到页面的 style 标签。并且这三个 loader 还是以链式调用形式加载的

      module.exports = {
            //...
            module: {
                rules: {
                    test: /\.less$/i,
                    use: ["css-loader","style-loader","less-loader"],
                },
            },
      }
  • Loader 的个性:

    • 链式执行(前一个 loader 的输入可能是另一个 loader 的输出)
    • 反对异步执行
    • 分为 normal 和 pitch 两种模式
  • 编写 Loader

    • 一个没有任何性能的 loader:

      module.exports = function(source, sourceMap?, data?){
        //source 是 loader 的输出也可能是前一个 loader 的输入
        return source;
      };
    • 在 webpack 中调用这个 loader:

      module.exports = {
          //...
          module: {
              rules: [
                {
                  test: /\.js$/,
                  use: [path.join(__dirname, './loader')]
                },
              ],
          },
      }
  • 罕用 Loader

Plugin 组件

  • Webpack 很多性能是靠插件实现的
  • 很多出名工具像 VS Code、Webstorm 等都设计了所谓的插件架构,Webpack 自身很多性能也是基于插件实现的
  • 不应用插件的话会有很多毛病:

    • 新人须要理解整个流程细节,上手老本高性能迭代老本高,牵一动员全身
    • 性能僵化,作为开源我的项目而言不足成长性
    • 也就是心智老本高、可维护性低、生命力弱
  • 插件架构的精华:对扩大凋谢、对批改关闭
  • 插件的应用:

    • 例如 npm i -D webpack-dashboard
    • 引入和应用插件:

      // import the plugin
      const DashBoardPlugin = require("webpack-dashboard");
      
      // add it to your webpack configuration plugins
      module.exports = {
        // ...
        plugins : [new DashBoardPlugin()],
        // ...
      };
  • 编写一个插件

    • 插件围绕‘钩子’开展,钩子的作用在编译的某个环节触发钩子,某种程度上能够了解为事件

      class SomePlugin {apply(compiler){compiler.hooks.thisCompilation.tap('SomePlugin', (compilation) => {})
        }
      }
    • 钩子的外围信息:

      • 机会:编译过程的特定节点,Webpack 会以钩子模式告诉插件此刻正在产生什么事件
      • 上下文:通过 tapable 提供的回调机制,以参数形式传递上下文信息
      • 交互:在上下文参数对象中附带了很多存在 side effect 的交互接口,插件能够通过这些接口扭转
      • 机会:compier.hooks.compilation
      • 参数:compilation 等
      • 交互:dependencyFactories.set

如何学习 Webpack

退出移动版