前端工程化

小白 vs 实际的前端开发

  • 小白眼中的前端开发
    • 会写 HTML + CSS + JavaScript 就会前端开发
    • 需要美化页面样式,就拽一个 bootstrap 过来
    • 需要操作 DOM 或发起 Ajax 请求,就拽一个 jQuery 过来
    • 需要渲染模板结构,就用 art-template 等引擎模板
  • 实际的前端开发
    • 模块化( js 模块化、css 模块化、其他资源的模块化)
    • 组件化( 复用现有组件的 UI 结构、样式、行为)
    • 规范化( 目录结构的划分、编码规范化、接口规范化、文档规范化、Git 分支管理)
    • 自动化
      • 在开发中,会将webpack的开发环境进行分离,抽出来分成三个.js文件,分别是:
        • config目录
          • webpack.dev.config.js —-> 开发环境
          • webpack.prod.config.js —-> 生产环境
          • webpack.common.config.js —-> 通用配置
      • 抽离后需要将webpack.common.config.js文件分别导入开发和生产环境内
        • 安装:npm install webpack-merge -D
        • 导入:
          • const {merge} = require('webpack-merge')
          • const commonConfig = require('./webpack.common.config')
        • 使用
          • module.exports = merge(commonConfig, {项目配置内容})
      • 开发和生产环境的导入和使用方式相同
      • 配置中有些路径需要修改,有些不需要


webpack

  • webpack 是一个打包工具

    安装 webpack

    ```bash // 全局安装 npm install webpack webpack-cli -g

// 局部安装 npm install webpack webpack-cli -D

  1. <a name="P6aJV"></a>
  2. ## 使用webpack进行打包
  3. ```bash
  4. $ webpack
  1. # 方法1
  2. $ ./node_modules/.bin/webpack
  3. # 方法2
  4. $ npx webpack
  5. # 方法3
  6. # 1. 在 package.json 文件中添加以下配置
  7. "scripts": {
  8. "build": "webpack"
  9. }
  10. # 2. 在命令行执行
  11. $ npm run build
  12. # 方法4:指定打包入口以及出口
  13. $ npx webpack --entry ./src/main.js --output-path ./build

快速生成 package.json文件

  1. # 方法1
  2. npm init
  3. # 方法2
  4. npm init -y

mode 的可选值

  • development
    • 开发环境
    • 不会对打包生成的文件进行代码压缩和性能优化
    • 打包速度快,适合在开发阶段使用
  • production

    • 生产环境
    • 会对打包生成的文件进行代码压缩和性能优化
    • 打包速度慢,仅适合在项目发布阶段使用

      webpack.config.js 文件的作用

  • webpack.config.js 是 webpack 的培指文件

  • webpack 在真正开始打包构建之前,会先读取这个配置文件,从而基于给定的配置,对项目进行打包
  • 注意:由于 webpack 是基于 node.js 开发出来的打包工具,因此它的配置文件中,支持使用 node.js 相关的语法和模块进行 webpack 的个性化配置

    webpack 打包默认行为

  • 默认的打包入口文件为 src -> index.js

  • 默认的输出文件路径为 dist -> main.js
  • 注意:可以在 webpack.config.js 配置文件中修改默认行为

    自定义打包入口和出口

  • 在 webpack.config.js 配置文件中,通过 entry 节点指定打包的入口。通过 output 节点指定打包的出口。

  • 示例代码如下: ```javascript const path = require(‘path’) // 导入 node.js 中专门操作路径的模块

module.exprots = { entry: path.join(dirname, ‘./src/index.js’), // 打包入口文件的路径 output: { path: path.join(dirname, ‘./dist’), // 输出文件的存放路径 filename: ‘bundle.js’ // 输出文件的名字 } }

  1. <a name="NghLh"></a>
  2. ## webpack 插件
  3. - 安装和配置第三方插件,可以拓展 webpack 的能力,从而让 webpack 用起来更方便
  4. - 常用的 webpack 插件有两个:
  5. - webpack-dev-server
  6. - 类似于 node.js 阶段用到的 nodemon 工具
  7. - 当源代码被修改后,webpack 会自动进行项目的打包和构建
  8. - 安装:npm i webpack-dev-server@3.11.0 -D
  9. - 配置 webpack-dev-server
  10. - 修改 package.json -> scripts 中的 dev 命令
  11. ```javascript
  12. "script": {
  13. "dev": "webpack server", // script 节点下的脚本,可以通过 npm run 执行
  14. }
  • html-webpack-plugin
    • webpack 中的 HTML 插件(类似于一个模板引擎的插件)
    • 可以通过此插件自定制 index.html 页面的内容
    • 安装:npm i html-webpack-plugin@4.5.0 -D
    • 配置 html-webpack-plugin ```javascript // 1. 导入 HTML 插件,得到一个构造函数 const HtmlPlugin = require(‘html-webpack-plugin’)

// 2. 创建 HTML 插件的实例对象 const htmlPlugin = new HtmlPlugin({ template: ‘./src/index.html’, // 指定原文件的存放路径 filename: ‘./index.html’ // 指定生成的文件的存放路径 })

module.exports = { plugins: [htmlPlugin], // 3. 通过 plugins 节点,使 htmlPlugin 插件生效 }

  1. <a name="NGSkp"></a>
  2. ## devServer 节点
  3. - 在 webpack.config.js 配置文件中,可以通过 devServer 节点对 webpack-dev-server 插件进行更多的配置
  4. - 示例代码如下:
  5. ```javascript
  6. devServer: {
  7. open: true, // 初次打包完成后,自动打开浏览器
  8. host: '127.0.0.1', // 是是打包所用的主机地址
  9. port: 8080 // 是是打包所使用的端口号
  10. }

Proxy解决本地跨域

  1. // webpack.config.js
  2. module.exports = {
  3. devServer: {
  4. proxy: {
  5. "/api": {
  6. target: "http://localhost:8888",
  7. pathRewrite: { // 重写
  8. "^/api": ""
  9. }
  10. }
  11. }
  12. }
  13. }

resolve

extensions配置文件后缀解析

  • 作用:打包时会自动匹配不带后缀的文件,并进入对应的路径目录进行查找,如有匹配则会自动添加该后缀
    1. module.exports = {
    2. resolve: {
    3. extensions: [".wasm", ".mjs", ".js", ".json"], // 默认值
    4. extensions: [".js", ".json", ".mjs", ".vue", ".ts", ".jsx", ".tsx"]
    5. }
    6. }

    alias配置路径别名

    1. module.exports = {
    2. resolve: {
    3. alias: {
    4. "@": path.resolve(__dirname, "./src")
    5. }
    6. }
    7. }

webpack插件

ClearWebpackPlugin

  • 作用:打包时自动删除原有的指定打包文件,重新生成新的打包文件
    1. npm install clear-webpack-plugin -D
    ```javascript // webpack.config.js

// 导入 const { ClearWebpackPlugin } = require(‘clear-webpack-plugin’);

// 使用 module.exports = { plugins: [ new ClearWebpackPlugin() ] }

  1. <a name="epWiv"></a>
  2. ## HtmlWebpackPlugin
  3. - 作用:打包`index.html`文件
  4. ```bash
  5. npm install html-webpack-plugin -D
  1. // webpack.config.js
  2. // 导入
  3. const HtmlWebpackPlugin = require('html-webpack-plugin')
  4. // 使用(默认打包文件为原有的index.html文件)
  5. module.exports = {
  6. plugins: [
  7. new HtmlWebpackPlugin()
  8. ]
  9. }
  10. // 扩展使用(自定义打包的index.html文件路径)
  11. module.exports = {
  12. plugins: [
  13. new HtmlWebpackPlugin({
  14. template: 'index.html文件路径'
  15. })
  16. ]
  17. }

DefinePlugin

该插件是webpack内置的

前言:

在使用HtmlWebpackPlugin插件时可能会遇到报错问题,可能是因为BASE_URL常量没有被定义

作用

解决HtmlWebpackPlugin报错问题:BASE_URL常量未定义

  1. // webpack.config.js
  2. // 导入
  3. const { DefinePlugin } = require('webpack')
  4. // 使用
  5. module.exports = {
  6. plugins: [
  7. new DefinePlugin({
  8. BASE_URL: "'./'" // 打包后BASE_URL将变成./
  9. })
  10. ]
  11. }

CopyWebpackPlugin

作用

public文件夹下的内容复制到指定的打包文件中

  1. // webpack.config.js
  2. // 导入
  3. const CopyWebpackPlugin = require('copy-webpack-plugin')
  4. // 使用
  5. module.exports = {
  6. plugins: [
  7. new CopyWebpackPlugin({
  8. patterns: [ // 所需要复制文件的对象,可以有多个
  9. {
  10. from: "public", // 复制的地址
  11. to: "./", // 复制到的地址(一般不写)
  12. globOptions: {
  13. ignore: [ // 打包复制所忽略的文件
  14. "**/index.html"
  15. ]
  16. }
  17. }
  18. ]
  19. })
  20. ]
  21. }

箭头函数转换:@babel/plugin-transform-arrow-functions

  1. npm install @babel/plugin-transform-arrow-functions -D
  1. $ npx babel demo.js --out-file test.js --plugins=@babel/plugin-transform-arrow-functions
  2. # demo.js:需要转换的文件
  3. # test.js:转换后的文件

块级作用域:@babel/plugin-transform-block-scoping

  1. npm install @babel/plugin-transform-block-scoping -D
  1. $ npx babel demo.js --out-file test.js --plugins=@babel/plugin-transform-block-scoping
  2. # demo.js:需要转换的文件
  3. # test.js:转换后的文件

loader和plugin的区别

  • loader:加载模块时,通过text去匹配该模块,并且使用和处理该模块
  • plugins:可以在webpack中做任何事情,贯穿整个webpack的生命周期

loader

  • 在实际开发过程中,webpack 默认只能打包处理以 .js 后缀名结尾的模块
  • 非 .js 后缀结尾的模块,webpack 默认处理不了,需要调用 loader 加载器才可以正常打包,否则会报错

    作用

  • 协助 webpack 打包处理特定的文件模块

    • css-loader:可以打包处理 .css 相关的文件
    • less-loader:可以打包处理 .less 相关的文件
    • babel-loader:可以打包处理 webpack 无法处理的高级 JS 语法

image.png

打包处理 css 文件

  • 安装:

    1. npm i style-loader@2.0.0 css-loader@5.0.1 -D
  • 在 webpack.config.js 的 module -> rules 数组中,添加 loader 规则如下:

    1. module: { // 所有第三方文件模块的匹配规则
    2. rules: [ // 文件后缀名的匹配规则
    3. { test: /\.css$/, use: ['style-loader', 'css-loader'] }
    4. ]
    5. }
  • test 表示匹配的文件类型,use 表示对应要调用的 loader

  • 注意:

    • use 数组中指定的 loader 顺序是固定的,不可变的
    • 多个 loader 调用顺序是:从后往前调用

      打包处理 less 文件

  • 安装:npm i less-loader@7.1.0 less@3.12.2 -D

  • 在 webpack.config.js 的 module -> rules 数组中,添加loader 规则如下:

    1. module: { // 所有第三方文件模块的匹配规则
    2. rules: [ // 文件后缀名的匹配规则
    3. { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }
    4. ]
    5. }

    打包处理样式表中与 url 路径相关的文件

  • 安装:npm i url-loader@4.1.1 file-loader@6.2.0 -D

  • 在 webpack.config.js 的 module -> rules 数组中,添加 loader 规则如下:

    1. module: { // 所有第三方文件模块的匹配规则
    2. rules: [ // 文件后缀名的匹配规则
    3. { test: /\.jpg|png|gif$/, use: ['url-loader?limit=22229'] }
    4. ]
    5. }
  • loader 的参数项:

    • limit 用来指定图片的大小,单位是字节(byte)
    • 只有 ≤ limit 大小的图片,才会被转为 base64 格式的图片

      打包处理 js 文件中的高级语法

  • webpack 只能打包处理一部分高级的 JavaScript 语法

  • webpack 无法处理的高级 JavaScript 语法需要借助于 babel-loader 进行打包处理
  • webpack 无法处理下面的 JavaScript 代码: ```javascript class Person { // 通过 static 关键字,为 Person 类定义了一个静态属性 info // webpack 无法打包处理“静态属性”这个高级语法 static info = ‘person info’ }

console.log(Person.info)

  1. - 配置 babel-loader
  2. ```javascript
  3. {
  4. test: /\.js$/,
  5. // exclude 为排除项
  6. // 表示 babel-loader 只需处理开发者编写的 js 文件,不需要处理 node_modules 下的 js 文件
  7. exclude: /node_modules/,
  8. use: {
  9. loader: 'babel-loader',
  10. options: {
  11. // 声明一个 babel 插件,此插件用来转化 class 中的高级语法
  12. plugins: ['@babel/plugin-proposal-class-properties'],
  13. },
  14. },
  15. }

打包处理(编译).vue文件

  1. npm install vue-loader@next @vue/compoler-sfc -D
  1. // webpack.config.js
  2. const { VueLoaderPlugin } = require('vue-loader/dist/index')
  3. module.exports = {
  4. module: {
  5. rules: [
  6. {
  7. test: /\.vue$/,
  8. loader: "vue-loader"
  9. },
  10. ]
  11. },
  12. plugins: [
  13. new VueLoaderPlugin()
  14. ]
  15. }

Babel

  • babel为一个独立的工具,不和webpack等构建工具配置来单独使用
  • 在命令行尝试使用babel,需要安装如下库:
    • @babel/core:babel的核心代码,必须安装
    • @babel/cli:可以在命令行使用babel

      安装

      1. npm install @babel/core @babel/cli -D

      使用

      1. # 局部安装使用
      2. $ npx babel demo.js --out-dir dist
      3. # demo.js 为需要打包的文件或目录
      4. # dist 为需要打包到的目录
      5. # --out-dir 为打包到的地址为文件夹形式
      6. # --out-file 为打包到的地址为文件形式

      Babel预设

      1. npm install @babel/preset-env -D
      1. $ npx babel demo.js --out-file test.js --presets=@babel/preset-env

      打包发布

  1. 开发环境下,打包生成的文件存放与内存中,无法获取到最终的打包生成的文件
  2. 开发环境下,打包生成的文件不会进行代码压缩和性能优化

    配置 webpack 的打包发布

  • 在 package.json 文件的 scripts 节点下,新增 build 命令如下: ```javascript “scripts”: { “dev”: “webpack serve”, “build”: “webpack —mode production” }

// —mode 是一个参数项,用来指定 webpack 的运行模式 // production 表示生产环境,会对打包生成的文件进行代码压缩和性能优化

  1. > 注意:通过 --model 指定的参数项,会覆盖 webpack.config.js 中的 model 选项
  2. <a name="QpjD4"></a>
  3. # Source Map
  4. <a name="tpNOY"></a>
  5. ## 什么是 Source Map
  6. - Source Map 就是一个信息文件,里面存储着位置信息
  7. - Source Map 文件中存储着代码压缩混淆前后的对应关系
  8. - 方便后期调试
  9. <a name="b5H3z"></a>
  10. ## 开发环境下的 Source Map
  11. - 开发环境下,webpack 默认启用了 Source Map 功能
  12. - 程序运行出错时,可以直接在控制台提示错误行的位置,并定位到具体的源代码
  13. - 开发环境下,推荐在 webpack.config.js 中添加如下的配置,即可保证运行时报错的行数与源代码的行数保持一致
  14. ```javascript
  15. module.exports = {
  16. mode: 'development', // mode 用来指定构建模式,可选值有 development 和 production
  17. devtool: 'eval-source-map', // source-map 调错,仅在开发环境下使用
  18. }

生产环境下的 Source Map

  • 生产环境下,如果省略了 devtool 选项,则最终生成的文件中不包含 Source Map
  • 只想定位报错的具体行数,且不想暴露源码,可以将 devtool 的值设置为 nosources-source-map

    1. module.exports = {
    2. mode: 'development', // mode 用来指定构建模式,可选值有 development 和 production
    3. devtool: 'nosources-source-map'
    4. }
  • 想定位报错的同时展示具体报错的源码,可以将 devtool 的值设置为 source-map

    1. module.exports = {
    2. mode: 'development', // mode 用来指定构建模式,可选值有 development 和 production
    3. devtool: 'source-map'
    4. }