前端工程化-Webpack 基础-打包 HTML、JS 和图片

以下皆为拉勾教育课件内笔记

打包 HTML

生成 HTML

html-webpack-plugin,该插件用来创建 HTML 文件,创建的 HTML 文件默认引⼊打包后的所有资源文件。复制 HTML 到打包目录、确保 HTML 中的路径正确(例如:HTML 标签中的 src )详情查看:https://www.npmjs.com/package/html-webpack-plugin

安装:

npm i html-webpack-plugin -D # webpack 5
npm i html-webpack-plugin@4 -D # webpack 4

引入:

const HtmlWebpackPlugin = require('html-webpack-plugin')

配置:
在 webpack.config.js 的 plugins 插件中添加 HtmlWebpackPlugin

plugins: [ 
  new HtmlWebpackPlugin() // 添加这⼀⾏ 
]

执行命令:

webpack

设置 HTML模板

plugins: [ 
  // ⽤于⽣成 index.html 
  new HtmlWebpackPlugin({ 
    template: './src/index.html', // 指定 HTML 的模板 
  }) 
]

声明模板

 
 
 
   
   
   
  Demo 
 
 
  

Hello Webpack

设置 HTML 配置项

少量配置可以在 HtmlWebpackPlugin 中指定
大量配置建议指定 HTML 文件的模板

plugins: [ 
  // ⽤于⽣成 index.html 
  new HtmlWebpackPlugin({
    template: './src/index.html', // 指定 HTML 的模板 
    title: 'Webpack Plugin Sample', // 添加 HTML 的 title 
    meta: { // 添加 HTML 的 meta 
      viewport: 'width=device-width, initial-scale=1.0' 
    } 
  }), 
  // ⽤于⽣成 about.html 
  new HtmlWebpackPlugin({ 
    filename: 'about.html' // 指定声明的⽂件名,如果有多个模板,可以实例化多次 
  }) 
]

声明 HTML 模板(其中的变量比如 title 使用 EJS 语法)
EJS -- 嵌入式 JavaScript 模板引擎 | EJS 中文文档 (bootcss.com)




  
   
  
  <%= htmlWebpackPlugin.options.title %>


  

<%= htmlWebpackPlugin.options.title %>

压缩 HTML

除了创建模板文件外,htmlWebpackPlugin 还可以通过配置,实现压缩 HTML 的效果,minify 选项可以配置压缩的内容。

plugins: [ 
  new CleanWebpackPlugin(), 
  new HtmlWebpackPlugin({
    template: "./src/index.html", 
    title: "Webpack Demo666",
    minify:{ 
      removeRedundantAttributes: true, // 删除多余的属性 
      collapseWhitespace: true, // 折叠空⽩区域 
      removeAttributeQuotes: true, // 移除属性的引号 
      removeComments: true, // 移除注释 
      collapseBooleanAttributes: true // 省略只有 boolean 值的属性值 例如:readonly checked 
    }
  }),
]

打包 JS

编译

babel
安装 babel-loader:npm install babel-loader @babel/core @babel/preset-env -D

@babel/core 包含 Babel 转换的核⼼ API
@babel/preset-env 包含最新 JS 语法的转换规则
babel-loader Webpack 中,转换 JS 的加载器

babel 结构:

添加配置:
启用 babel-loader 后 ES6+ 的语法会转成 ES5。但是 babel 只会对基本语法进行转移。像 promise 这样的高级语法,Babel 就不能转换。

const path = require('path') 
module.exports = {
  mode: 'none', 
  entry: './src/main.js', 
  output: { 
    filename: 'bundle.js', 
    path: path.join(__dirname, 'dist'), 
    publicPath: 'dist/' 
  }, 
  module: { 
    rules: [ 
      { 
        test: /\.m?js$/i, 
        exclude: /node_modules/, // 排除不需要打包的⽬录 
        use: { 
          loader: 'babel-loader', 
          options: { 
            presets: ['@babel/preset-env'] 
          } 
        } 
      } 
    ] 
  } 
}

polyfill
安装:npm i @babel/polyfill -D
使用:在入口文件中引入 @babel/polyfill

import '@babel/polyfill' 
// ......

@babel/polyfill 会对所有的 JS 新语法进行转译(没用到的新语法也会被转译),因此打包后的 JS 会 非常大

core-js
core-js 可以按需转译(即只转译用到的新语法)
安装:npm i core-js -D
使用:

const path = require('path') 
module.exports = {
  mode: 'none', 
  entry: './src/main.js', 
  output: { 
    filename: 'bundle.js', 
    path: path.join(__dirname, 'dist'), 
    publicPath: 'dist/' 
  }, 
  module: { 
    rules: [ 
      { 
        test: /\.m?js$/i, 
        exclude: /node_modules/, // 排除不需要打包的⽬录 
        use: { 
          loader: 'babel-loader', 
          options: { 
            // presets: ['@babel/preset-env'] 
            presets: [
              '@babel/preset-env',
              {
                // 按需加载
                useBuiltIns: 'usage',
                // 指定 core-js版本
                corejs: {
                  version: 3
                },
                // 指定兼容性做到哪个版本浏览器
                targets: {
                  chrome: '60',
                  firefox: '60', 
                  ie: '9', 
                  safari: '10', 
                  edge: '17'
                }
              }
            ]
          } 
        } 
      } 
    ] 
  } 
}

格式校验

之前进行格式校验使用的是 eslint-loader,但 eslint-loader 已经废弃。
现在推荐使用 eslint-webpack-plugin 来进行 JS 的格式校验
详情查看:https://www.npmjs.com/package/eslint-webpack-plugin

安装:npm i eslint eslint-config-airbnb-base eslint-webpack-plugin eslint-plugin-import -D

说明

  • eslint(用来对 JS 进行格式校验的工具)

    • https://eslint.org/
  • eslint-config-airbnb-base(格式校验规则)

    • https://github.com/airbnb/javascript
    • https://www.npmjs.com/package/eslint-config-airbnb-base
  • eslint-webpack-plugin(Webpack 的 eslint 插件)

    • https://www.npmjs.com/package/eslint-webpack-plugin
  • eslint-plugin-import(⽤于在 package.json 中读取 eslintConfig 配置项)

使用:

const ESLintPlugin = require('eslint-webpack-plugin'); 
module.exports = { 
  // ... 
  plugins: [new ESLintPlugin(options)], 
  // ... 
};

设置配置项:

const ESLintPlugin = require('eslint-webpack-plugin'); 
module.exports = { 
  plugins: [ 
    # 使⽤ 配置项都可以在 eslint-webpack-plugin 的 github 上找到
    new ESLintPlugin({ 
      fix: true, 
      extensions: ['js', 'json', 'coffee'], 
      exclude: '/node_modules/'
    }), 
  ] 
};

指定 eslint 配置:

指定 eslint 配置的方式有多种

  • 在 package.json 中,通过 eslintConfig 指定
  • 在项目根目录下,通过 .eslintrc 指定(.eslintrc 可以通过 eslint --init 命令生成)
// package.json
"eslintConfig": { 
  "extends": "airbnb-base",
  #!!!!如果没使⽤ alias 下⾯的不⽤配置!!!!! 
  "settings": {
    "import/resolver": { 
      "webpack": { 
        "config": "webpack.config.js" 
      } 
    } 
  } 
}

打包图片

样式中的图片引入

打包图片时,最常用两个 loader

  • file-loader 将用到的图片直接复制到 dist 目录下,过滤掉不用的图片
    https://www.npmjs.com/package/file-loader
  • url-loader 将小于指定大小的图片,转成 base64,超过指定大小的图片依然使用 file-loader 进行复制,转成 base64 字符串后,图片会跟 js 一起加载(减少图片的请求次数)
    https://www.npmjs.com/package/url-loader

安装:npm install file-loader url-loader -D

配置:

const path = require('path'); 
const HtmlWebpackPlugin = require('html-webpack-plugin') 
module.exports = { 
  // 打包模式 
  mode: 'development', 
  // ⼊⼝⽂件
  entry: './src/index.js', 
  // 输出  
  output: { 
    path: path.resolve(__dirname, 'dist'), 
    filename: 'main.bundle.js', 
  }, 
  // loader 配置 
  module: { 
    rules: [ 
      { 
        test: /\.(png|gif|jpe?g)$/,
        use: {
          loader: 'url-loader', 
          options: { 
            limit: 2 * 1024, // 2 kb 设置图⽚⼤⼩,⼩于该数值的图⽚会被 转成 base64
            // 保留原图片名称及后缀名 
            name: "images/[name].[ext]"  // [name] 是原名称,[ext]是原后缀名
          } 
        }, 
      } 
    ] 
  },
  // plugin 配置
  plugins: [ 
    new HtmlWebpackPlugin({ 
      title: "Webpack Demo",
      template: "./src/index.html" 
    }) 
  ] 
};

上述配置可以处理样式文件中的图片引入,例如:

body { 
  /* background-color: #dbf; */ 
  background: url(./images/1.jpg) no-repeat; 
}

HTML 中的图片引入

html-loader 将 HTML 导出为字符串(负责引入 img,从而能被 url-loader 进行处理)
https://www.npmjs.com/package/html-loader

安装:npm install html-loader -D

配置:

const path = require('path'); 
const HtmlWebpackPlugin = require('html-webpack-plugin') 

module.exports = { 
  // 打包模式 
  mode: 'development',
  // ⼊⼝⽂件
  entry: './src/index.js', 
  // 输出 
  output: { 
    path: path.resolve(__dirname, 'dist'), 
    filename: 'main.bundle.js', 
  }, 
  // loader 配置 
  module: { 
    rules: [ 
      { 
        test: /\.(png|gif|jpe?g)$/, 
        use: { 
          loader: 'url-loader', 
          options: { 
            limit: 2 * 1024, // 2 kb
            name: "images/[name].[ext]", 
            // url-loader 默认采⽤ ES Module 进⾏解析,⽽ html-loader 引⼊图⽚使⽤的是 CommonJS 
            // 解决:关闭 url-loader 的 ES Module 解析,使⽤ CommonJS 进⾏解析 
            esModule: false
          } 
        }, 
      }, 
      { 
        test: /\.(htm|html)$/i, 
        // 负责处理 HTML 中的 img 图⽚ 
        loader: 'html-loader',
        options: { 
          // webpack4 中只需要在 url-loader 配置 esModule:false 
          // webpack5 需要 html-loader 也配置 esModule:false 
          esModule: false 
        } 
      } 
    ] 
  }, 
  // plugin 配置 
  plugins: [ 
    new HtmlWebpackPlugin({ 
      title: "Webpack Demo", 
      template: "./src/index.html"
    })
  ]
};

html-loader 与 html-webpack-plugin 冲突

问题:
入口页面中默认使用的 lodash 模板未被解析⽣效。 虽然 html-loader 可以解决 HTML 文件中的图片加载问题,但 HTML 中的 ejs 语法失效了。

原因:
htmlWebpackPlugin 会检查目标文件是否已经有 loader 处理,如果有其他 loader 处理, htmlWebpackPlugin 不再使用 lodash.template 去编译目标,直接返回 source。
这里,我们已经声明了通过 html-loader 来处理 html 文件,因此 ejs 语法失效

部分 htmlWebpackPlugin 的关键代码(位置:html-webpack-plugin/lib/loader.js)

const _ = require('lodash'); 

module.exports = function (source) { 
  // Get templating options 
  const options = this.getOptions(); 
  const force = options.force || false;
  const allLoadersButThisOne = this.loaders.filter((loader) => lo ader.normal !== module.exports); 

  // 如果有其他 loader 进⾏处理,则直接返回 
  if (allLoadersButThisOne.length > 0 && !force) { 
    return source; 
  } 

  // 否则使⽤ lodash.template 的模板进⾏语法解析 
  const template = _.template(source, { 
    interpolate: /<%=([\s\S]+?)%>/g, 
    variable: 'data', ...options 
  });

解决:
将模板文件统一为 ejs 格式,先通过 htmlWebpackPlugin 处理 ejs 文件,然后 html-loader 继续做后续处理。

  1. 修改模板⽂件后缀(src/index.html => src/index.ejs)

  2. 修改配置中的模板名称

    plugins: [
      new CleanWebpackPlugin(),
      new HtmlWebpackPlugin({
        template: "./src/index.ejs", // 这⼀⾏
        title: "Webpack Demo", 
      })
    ]
    
  3. 将模板文件中的图片引入,改成 ejs 语法

     
     
     
    
    

你可能感兴趣的:(前端工程化-Webpack 基础-打包 HTML、JS 和图片)