前端工程化-预处理器| 青训营笔记

159 阅读5分钟

这是我参与「第四届青训营 」笔记创作活动的的第3天

何为预处理?

预处理一般是指在程序源代码被翻译为目标代码的过程中,生成之前的过程。典型地,由预处理器(preprocessor) 对程序源代码文本进行处理,得到的结果再由编译器核心进一步编译。这个过程并不对程序的源代码进行解析,但它把源代码分割或处理成为特定的单位——(用C/C++的术语来说是)预处理记号(preprocessing token)用来支持语言特性(如C/C++的宏调用)。

上方为官方解释,但我认为对于前端来说,预处理器就是将高级别的JS或CSS代码转换为低级别JS或CSS代码的一个工具而已。 主要分两类:

  • JS预处理器
  • CSS预处理器

JS预处理器

典型Babel

Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。
下面列出的是 Babel 能为你做的事情:
1.语法转换
2.通过 Polyfill 方式在目标环境中添加缺失的特性 (通过 @babel/polyfill 模块)
3.源码转换 (codemods)

工作流程

大致可以分为三个阶段:

parsing:内部的 babylon 负责将es6代码进行语法分析和词法分析后转换成抽象语法树
transforming:内部的 babel-traverse 负责对抽象语法树进行变换操作
printing:内部的 babel-generator 负责生成对应的代码

插件 plugins

babel 本身是一个工具链,而最终的实现是用来完成的,插件是一个 js 程序用来指示 babel 怎么对 js 进行转换。 插件分两种:

转换插件:用于转换代码,比如 arrow-functions 转换钩子函数
语法插件:用于解析特定类型的语法,比如 jsx。使用转换插件时会自动启用对应的语法插件。

预设 presets

另外插件组成的数组叫预设,可以一次性使用多个插件并共享选项。

常用预设 preset-env

preset-env是一组babel相关的plugin集合(如将箭头函数转换为functionletconst转换为var等一些列插件的集合)。

注意!这里的转换仅限于语法上的转换,而不涉及到API的转换,如PromiseArray.prototype.includes等都不能转换。这就需要引出@bable/polyfill

引入@bable/polyfill方式如下:

module.exports = {
  presets: [
    [
      "@babel/env",
      {
        useBuiltIns: "usage", // 实现按需加载
        corejs: { 
          version: 3, 
          /** 
          core-js 选项
          
          可选值为:false, 2, 3 or { version: 2 | 3, proposals: boolean }, defaults to false.
          通过提供了一个沙箱环境,利用 core-js 中实现的别名来 polyfill 对应功能,避免了污染全局。各个可选值表示以及对应依赖的 runtime helper 包分别为
          
          false 不会 polyfill,@babel/runtime
          2,依赖 core-js2,只支持全局变量和静态属性,@babel/runtime-corejs2
          3,在 2 的基础上添加了实例属性,并且可以利用 proposals 选项启用提案的 polyfill,@babel/runtime-corejs3
          
            **/
          proposals: true 
        }
      }
    ]
  ],
  plugins: []
};

新起之秀SWC

SWC 是一个可扩展的基于 Rust 的平台,适用于下一代快速开发工具。它被Next.js,Parcel和Deno等工具以及Vercel,ByteDance,腾讯,Shopify等公司使用。

SWC 可用于编译和捆绑。对于编译,它采用使用现代JavaScript功能的JavaScript TypeScript文件,并输出所有主要浏览器都支持的有效代码。

SWC在单个线程上比Babel快20倍,在四个内核上比Babel快70倍

CSS预处理器

Postcss

Postcss 是一个使用js插件来转换样式的工具,Postcss 的插件会检查你的css。

其中最常用的插件莫过于 autoprefixer 这个插件了,这个插件会添加浏览器前缀,避免了手动写-webkit-这样的代码。 在 Postcss 中还有很多好用的插件,比如可以自动转换 px 来进行适配不同显示器的 postcss-px-to-viewport,可以自动对Css属性依照设定的规则进行排序的 postcss-sorting 等等。

当然这已经在上篇所说的Vite中集成了

Autoprefixer

不加任何prefix的通常写法。

.example {
    display: grid;
    transition: all .5s;
    user-select: none;
    background: linear-gradient(to bottom, white, black);
}

Autoprefixer将使用基于当前浏览器支持的特性和属性数据去为你添加前缀。
你可以尝试下Autoprefixer的demo:Autoprefixer CSS online image.png 由上图可以看出,像没有浏览器差异已经完全符合W3C标准的css2.1属性display,position等,Autoprefixer不会为其加前缀,而像css3属性transform就会为其加前缀,其中--webkit是chrome和safari前缀,--ms则是ie的前缀,像firefox由于已经实现了对transform的W3C标准化,因此使用transform即可。

因此Autoprefixer是一个非常有用的加速前端开发的一个工具。

使用配置(搭配打包工具)

由于我们项目使用Vite,咱只给出Vite配置,如下:

import vue from "@vitejs/plugin-vue";
import path from "path";
import { defineConfig } from "vite";
import autoprefixer from "autoprefixer";
import legacy from "@vitejs/plugin-legacy";

// https://vitejs.dev/config/
export default defineConfig({
  css: {
    postcss: {
      plugins: [autoprefixer()],
    },
  },
  plugins: [
    vue({
      reactivityTransform: true,
    }),
    legacy(),
  ],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

需注意在 package.json 中配置 browserslist

{
  "name": "@balabala/monitor-frontend",
  "version": "1.0.0",
  "type": "module",
  "license": "MIT",
  "scripts": {
    "dev": "lerna bootstrap && scripty",
    "build": "lerna bootstrap && scripty",
    "preview": "lerna bootstrap && scripty",
    "type-check": "vue-tsc --noEmit"
  },
  "dependencies": {
    "@balabala/monitor-api": "^1.0.0",
    "dayjs": "^1.11.4",
    "echarts": "^5.3.3",
    "font-awesome": "^4.7.0",
    "normalize.css": "^8.0.1",
    "pinia": "^2.0.19",
    "vue": "^3.2.37",
    "vue-datepicker-local": "^1.0.19",
    "vue-echarts": "^6.2.3",
    "vue-router": "^4.1.3"
  },
  "devDependencies": {
    "@types/echarts": "^4.9.16",
    "@vitejs/plugin-legacy": "^2.0.0",
    "@vitejs/plugin-vue": "^3.0.0",
    "autoprefixer": "^10.4.8",
    "eslint-plugin-vue": "^9.3.0",
    "vite": "^3.0.0",
    "vue-tsc": "^0.38.4"
  },
  "browserslist": {
    "production": [
      "defaults",
      "not IE 11"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version",
      "last 1 edge version",
      "last 1 ie version"
    ]
  }
}