构建现代JS工程环境

前言

前端的发展速度飞快,如今前端的工程体系和之前有很大的区别,本文我们先聊聊 Webpack 场景下处理 JavaScript 的三种常用工具:Babel、TypeScript、ESLint 的历史背景、功能以及接入 Webpack 的步骤,借助这些工具,我们能构建出更健壮、优雅的 JavaScript 应用。

Babel

ECMAScript 6.0 (简称ES6) 版本补充了大量提升 JavaScript 开发效率的新特性,包括 class类、块级作用域、 ES Module 方案、代理与反射等,使得 JavaScript 可以真正被用于编写复杂的大型应用程序,但我们知道现在的浏览器、Node 等 JavaScript 引擎或多或少存在兼容性问题。为此,现代 Web 开发流程中通常会引入 Babel 等转译工具。 Babel 是一个开源的 JavaScript 编译器,它可以将高版本的代码——如 ES6 的代码转译成可以在旧版本的JavaScript 引擎上运行的代码。举个例子:

// Babel转译前
const fn = () => {
	console.log('hello')
}

// Babel 转译后
"use strict";

var fn = function fn() {
  console.log('hello');
};

上面的例子中我们使用了 ES6 的箭头函数写法,经过 Babel 转译后在不支持箭头函数的 JavaScript 引擎上依然可以正常运行,由此可见 Babel 可以帮助我们在写Web应用时始终使用最新的 ECMAScript 语法,提高开发效率。

TypeScript

JavaScript 是一种弱类型语言,这使它具备一定的灵活性,但相应的也暴露出一些问题,比如我们使用运算符操作两个数据类型不同的变量时或者在一个对象中访问不存在的属性时,在 JavaScript 环境中,要在运行时才能发现问题,而如果在 TypeScript 环境下就能够让问题在编译阶段提前暴露:

上面的例子中,一个numer类型去减去一个string类型,在TypeScript编译过程中就报错提示了,这种类型检查的特性虽然一定程度上损失了语言本身的灵活性,但能够让问题提前暴露,确保运行阶段的类型安全性,特别适合用于构建多人协作的大型 JavaScript 项目,也因此,时至今日 TypeScript 依然是一项应用广泛的 JavaScript 超集语言。

ESLint

上面我们说到过,JavaScript 是一种高度灵活的、弱类型的脚本语言,这也意味着开发者的学习成本极低,只需要短暂的学习就可以开始构建简单应用。与其他编译语言相比,JavaScript 很难在编译过程中发现语法、类型等可能影响稳定性的错误,特别是在多人协作的复杂 Web 应用中,每个人代码风格不统一,语言本身的弱约束可能会对开发效率与质量产生不小的影响,ESLint 的出现正是为了解决这一问题。 ESLint 是一种扩展性极佳的 JavaScript 代码风格检查工具,它能够自动识别违反风格规则的代码并予以修复。例如下面的例子:

// ESLint修复前
const foo = "foo"
const bar = "bar"

// ESLint修复后
const foo = 'foo';
const bar = 'bar';

ESLint会根据配置的风格规则找出不符合的地方,予以告警,甚至自动修复。

在Webpack中使用

接下来我们借助 Babel + TypeScript + ESLint 搭建一套功能完备的 JavaScript 应用开发环境:

  1. 初始化并安装依赖:
npm init -y

npm i -D webpack webpack-cli
# babel 依赖
npm i -D @babel/core @babel/cli @babel/preset-env babel-loader
# TypeScript 依赖
npm i -D typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin @babel/preset-typescript
# ESLint 依赖
npm i -D eslint eslint-webpack-plugin
  1. 创建webpack.config.js文件,并配置如下内容:
const path = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');

module.exports = {
  // 入口
  entry: './src/index.ts',
  // 模式
  mode: 'development',
  // 是否生成 source map
  devtool: false,
  // 打包后输出
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      // 后缀为.ts的文件处理
      {
        test: /\.ts$/,
        use: {
          loader: 'babel-loader',
          options: {
            // 预设规则集 这里使用了@babel/preset-typescript
            // 这里只使用了预设规则集转译代码 并没有使用ts-loader
            presets: ['@babel/preset-typescript']
          }
        }
      }
    ]
  },
  // 插件
  // extensions 指定需要ESLint检查的文件扩展名
  plugins: [new ESLintPlugin({ extensions: ['js', '.ts'] })]
}
  1. 创建.eslintrc,配置ESLint:
{
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint"],
  "extends": ["plugin:@typescript-eslint/recommended"],
  "rules": {
    "@typescript-eslint/no-var-requires": 0
  }
}
  1. package.json中配置一条scripts
{
  // ...
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  // ...
}

之后只需要执行npm run build或者npx webpack即可开始打包。

const arr: number[] = [1, 3, 5];
const sum = arr.reduce((pre, cur) => pre + cur);
console.log(sum)
/******/ (() => { // webpackBootstrap
var __webpack_exports__ = {};
/*!**********************!*\
  !*** ./src/index.ts ***!
  \**********************/
const arr = [1, 3, 5];
const sum = arr.reduce((pre, cur) => pre + cur);
console.log(sum);
/******/ })()
;

至此,我们就搭建了一个支持 Babel + TypeScript + ESLint 的开发环境。

总结

本节介绍了 ESLint、TypeScript、Babel 三类工程化工具的历史背景以及他们的作用,以及在 Webpack 中接入三种工具的具体步骤。这三种工具各自补齐了 JavaScript 语言某些薄弱环节:

  • Babel:提供 JavaScript 语言转译能力,能在确保产物兼容性的同时,让我们大胆使用各种新的 ECMAScript 语言特性;
  • TypeScript:提供的数据类型检查能力,能有效提升应用代码的健壮性;
  • ESLint:提供的风格检查能力,能确保多人协作时的代码一致性。