从搭建 parcel 项目开始理解前端工程化 | 入门向

1,176 阅读9分钟

前言

这篇文章的目的是演示如何搭建一个简单可控的前端工程模板,并尽量用简短的语言让新手也能理解和掌握简单的前端工程化,但读者应该至少了解 JavaScript 和 Nodejs 的基础用法。为了减少大量无意义的项目配置我们选择 parcel 作为构建工具,作为面向工业用途的项目我们还需要使用 TypeScript 语言在开发时保证类型正确,最后通过 ESLintvscode 进行配合保证代码风格,三者搭配能够帮助我们在编译前就找出大部分潜在的代码问题。同样为了保证可控我们尽量使用库 cli 自带的命令来生成配置文件,在此基础上进行修改来构造我们自己的项目。

文中可能会出现很多的名词和概念,甚至会导致行文上缺少组织,如果你目前无法理解它们的用途可以先暂且略过,先按照文章的步骤搭建工程,等到有需要或是有空时再来搭配其它文章理解这些概念。因为我自己在学习前端的过程中发现,很多时候不是不想去学,而是面对知识点繁杂的前端工作完全无从下手,所以我宁愿把概念一股脑地塞进文章这样至少能给读者一点线索。

构建工具

首先创建项目目录,这里我使用 yarn 来进行包的安装和管理,你也可以自行使用 npm 作为替代,此处不另行展示。第三行的 yarn init 命令用来在当前目录下初始化 nodejs 工程并生成 package.json 配置文件。

mkdir parcel-eslint-template
cd parcel-eslint-template
yarn init
yarn add parcel-bundler typescript --dev

这里安装的 parcel 是一款及其易于使用号称零配置的打包工具,使用打包工具的意义在于:

文件格式转换:旧标准的 JavaScript 在类型和面向对象上的支持很薄弱,CSS 在大型项目中写起来过于繁琐,诸如此类的众多缺陷严重影响了开发效率。但它们都在各大浏览器上获得了垄断的地位以至于无法轻易被替代,于是开发者们发明了 TypeScript 和 SCSS 等语言,并通过将它们编译为 JavaScript、CSS 和 HTML 的方式来在各大浏览器平台运行。

通过 NPM 管理依赖:在此基础上就能在所有浏览器上获得像是 Python 一样简单易用的模块系统,你只需要运行命令 yarn add lodash,再在代码文件里通过类似 import _ from 'lodash' 的语句导入第三方依赖库即可,而不用到处寻找 bootstrap.css 或是 jquery.js 之类的分发文件并亲自管理储存和导入。

减轻网络负担:通过 <script src="index.js"></script> 这样的方式零碎地引入多个脚本会进行多次网络请求,对于旧版的 HTTP 协议来说会造成很大的负担。打包工具则将每个页面需要的所有脚本整合成单个文件,每个页面只需要进行一次网络请求即可获取到所需的代码,极大加快网页的载入速度。

parcel 至少对于中小型项目来说,相对于其它构建打包工具,可以让你避免很多繁杂的配置:以往要引入 .vue 或是 .pug 等格式的文件你需要先安装对应的依赖,再配置与打包构建工具兼容的 loader 等等,现在你只需要 import 'index.scss' 这样一行简单的代码即可,parcel 会帮助你安装需要的库并进行处理。这里我们为了便捷起见一起安装了 TypeScript,实际上就算我们没有手动安装,之后运行应用的时候 parcel 也会进行提示并安装。详细信息可以查看 parcel.js 的官网

基础结构

然后建立按照如下的文件结构:

src
  - add.ts
  - index.js
index.html
package.json

我们将 index.html 作为应用的入口,其它代码则统一放在 src 目录下。

package.json 中添加 scripts 配置项,这样我们在项目根目录下运行 yarn devnpm run dev 命令时就会自动执行 parcel index.html,随着项目复杂程度提高我们需要使用的命令越来越长的时候,定义这样快捷脚本的好处就能体现出来了,快捷脚本还能帮助其它贡献者了解你的项目。

package.json

{
  "name": "parcel-eslint-template",
  "version": "1.0.0",
  "main": "index.js",
  "author": "Asuka109",
  "license": "MIT",
  "scripts": {
    "dev": "parcel index.html"
  },
  "devDependencies": {
    "parcel-bundler": "^1.12.4",
    "typescript": "^4.0.2"
  }
}

整个应用我们只需要这一个 .html 文件,它将作为我们应用的网页入口和容器

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <!-- 各种框架的挂载容器,可以理解为各种由框架控制的动态内容 -->
  <!-- 都会附加在这个 div 上面进行渲染 -->
  <div id="app"></div>
  <!-- 引入代码入口,我们的所有代码都会被这个文件直接或间接调用 -->
  <script src="src/index.js"></script>
</body>
</html>

src/index.js

// 这里是我们所有代码的入口
// 之后的文章里我们还会从这里再进入 Vue 的应用入口

// 使用 ESM 语法导入代码模块中的函数
import { add } from './add'

// 文档载入完成后调用我们的主体代码
document.addEventListener('DOMContentLoaded', () => {
  const container = document.getElementById('app')
  container.textContent = add(1, 2)
})

src/add.ts

// 导出一个名为 add 的函数,这个函数可以被其它模块调用
// 这里还用上了 TypeScript 的类型标注语法
export function add (a: number, b: number): number {
  return a + b
}

运行我们先前设置好的命令 yarn dev,即可让 parcel 构建打包并启动一个本地开发服务器,简而言之这就是一个调试运行的功能。你可以随时修改源代码,只要检测到修改 parcel 就会立刻重新构建并更新网页,你可以实时看到你做出的更改。

❗ 注意:大部分现代浏览器都严格限制本地 HTML 文件的权限,也就是说双击打开网页文件的时候大概率是会报错的,要在你自己的电脑上查看编辑或生成的网页文件,必须要启动一个本地服务器程序。

yarn dev

这时访问 http://localhost:1234/ 应当能看到网页显示:3

parcel 的开发服务器默认会监听 1234 端口,但考虑到端口可能被占用,具体情况应该参考控制台的输出信息

配置代码检查

接下来我们来配置代码检查工具 ESLint,它会自动检查代码中存在的开发时 bug 并提示或强制进行修改,不仅仅是 统一双引号大括号换行强制块级作用域变量 这么简单,它还可以提供 禁止不变动的循环条件限制程序中允许的最大环路复杂度 等等复杂的检查能力。

很多教程在讲解配置 ESLint 会直接让读者复制粘贴一整段不明所以的配置项,这样的方式很容易导致各种预期外的效果。正确的方式应该是使用官方自带的 cli 直接自动生成配置文件,然后再在此基础上进行修改。

npxnpm 自带的一个功能强大的命令运行工具,它可以从网络上执行 npm 仓库里任何一个库的 cli 命令而不用特地下载安装这个库。比如这里我们就直接从 npm 仓库上执行了 ESLint 库附带的 eslint --init 命令,这个命令的作用就是帮助生成配置。

npx eslint --init

运行命令后你只需做一些简单的选择题即可完成配置,所有内容根据你的项目情况选择即可,下面的配置选项就是用来搭建一个基于 Vue + TypeScript 的应用。

√ How would you like to use ESLint? · style       
√ What type of modules does your project use? · esm
√ Which framework does your project use? · vue
√ Does your project use TypeScript? · Yes
√ Where does your code run? · browser, node
√ How would you like to define a style for your project? · guide
√ Which style guide do you want to follow? · standard    
√ What format do you want your config file to be in? · JavaScript
Checking peerDependencies of eslint-config-standard@latest       
Local ESLint installation not found.
The config that you've selected requires the following dependencies:

eslint-plugin-vue@latest @typescript-eslint/eslint-plugin@latest eslint-config-standard@latest eslint@>=6.2.2 eslint-plugin-import@>=2.18.0 eslint-plugin-node@>=9.1.0 eslint-plugin-promise@>=4.2.1 eslint-plugin-standard@>=4.0.0 @typescript-eslint/parser@latest
? Would you like to install them now with npm? » No

这里最后一个选项我选择 No 也就是不使用 npm 来安装依赖,我选择自己用 yarn 来安装依赖。

yarn add -D eslint-plugin-vue@latest @typescript-eslint/eslint-plugin@latest eslint-config-standard@latest eslint@>=6.2.2 eslint-plugin-import@>=2.18.0 eslint-plugin-node@>=9.1.0 
eslint-plugin-promise@>=4.2.1 eslint-plugin-standard@>=4.0.0 @typescript-eslint/parser@latest

就在写这篇文章的当天 typescript-eslint 更新了一个小版本,这个版本会导致 ecmaVersion 配置错误,如果你也遇到类似的问题可以按照 issues 里给出的方案参考下面的代码修改配置,如果没有出现问题就不需要修改配置

详情见:github.com/typescript-…

.eslintrc.js

module.exports = {
  env: {
    browser: true,
    es2020: true,
    node: true
  },
  extends: [
    'plugin:vue/essential',
    'standard'
  ],
  parserOptions: {
    ecmaVersion: 2020,
    parser: '@typescript-eslint/parser',
    sourceType: 'module'
  },
  plugins: [
    'vue',
    '@typescript-eslint'
  ],
  rules: {
  }
}

类似地我们也通过 cli 初始化 TypeScript 的配置文件,构建时 parcel 会调用 typescript 库来将 TypeScript 代码转换为 JavaScript 代码,这个过程就会按照 tsconfig.json 中的配置来进行。

npx tsc --init

默认生成的配置文件会带有注释过的所有配置项目,这里只保留几条需要的项目。

tsconfig.json

{
  "include": [
    "src/**/*.ts"
  ],
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */

    /* Basic Options */
    // "incremental": true,                   /* Enable incremental compilation */
    "target": "ES2020",                       /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "es2020",                       /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */

    /* Strict Type-Checking Options */
    "strict": true,                           /* Enable all strict type-checking options. */
    "sourceMap": true,
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */

    /* Advanced Options */
    "skipLibCheck": true,                     /* Skip type checking of declaration files. */
    "forceConsistentCasingInFileNames": true  /* Disallow inconsistently-cased references to the same file. */
  }
}

你可以在命令行中运行 npx eslint 来检查语法问题,或者为 vscode 中安装 ESLint 拓展 来让 vscode 支持编辑器内的智能语法提示。

UTOOLS1599060623754.png

最后

这样我们就搭建出了一个现代化的前端项目雏形,目前 parcel 还不支持 vue@next,等到过两天 Vue 3.0 正式发布再写一篇搭建 Vue 工程的后续教程。

其实现在 ESM 模块系统和新的 HTTP 协议在浏览器上的发展和推广已经接近成熟,市面上出现了 snowpack 和尤大钦定的 vite 这样不需要打包的构建工具,它们的效率比现有的工具更上一个台阶而且一定会成为下一代的前端标准,之后有机会也会写文章介绍一下这类工具。

文章难免有各种问题,各位如果有发现疏漏请一定不吝赐教评论指出,谢谢!