为什么要学习 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.jsmodule.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 pluginconst DashBoardPlugin = require("webpack-dashboard");// add it to your webpack configuration pluginsmodule.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