前言

以前在 Webpack 学习笔记 有稍微介绍过它们。这篇是单独整理版。

参考

一文彻底读懂ESLint

你的ESLint真的需要Prettier吗?

搞懂eslint和prettier等的关系

简单介绍

Prettier 是一个 formatting 工具,目的是方便统一代码格式,比如使用 single quote 还是 double quote?

它支持许多语言,包括 JS、TS、CSS、Sass、HTML、JSON 等等。

ESLint 是 JS / TS 代码检查器。它用于保证代码质量,通过 2 个方式

  1. 统一格式 (formating),这部分的功能和 Prettier 是一样的。 只是 ESLint 比较 configable。Prettier 是出了名的“固执”,很多规范你只能跟随官方的格式,它不允许你做配置。

  2. code quality,这点是 Prettier 没有的功能。

比如 function declare 了一个 parameter,但 function 内却完全没有调用到。(这通常是因为忘记移除)

这些都会被检测出来。在提交代码前我们就可以进行修改,这样就保证了代码质量。

Stylelint 也是这类检查器,它用于 CSS / Sass

Prettier vs ESLint & Stylelint

Prettier 的 formatting 功能, ESLint 和 Stylelint 都有。但是通常我们是用 Prettier 做 formatting 然后用 ESLint 和 Stylelint 做 code quality control。

而且 Stylelint v15.0 后,它自己阉割了 formatting 的功能,官方也叫你用 Prettier。

所以下面 ESLint 和 Stylelint 都是搭配 Prettier 使用的。

Prettier

Command-line

首先全局安装 prettier package (Prettier 基于 Node.js)

npm install prettier --global

创建项目

yarn init

创建一个 index.ts

const value = 'value';

Prettier 支持很多种语言的格式,这里只是随便拿 TS 做例子。

运行

prettier index.ts

效果

Prettier 不会告诉你,哪个地方格式错了,它只会输出一个格式化后的内容。

注意看, value 从原本的 single quote 变成了 double quote。(没错,Prettier 默认 TS 是用 double quote 的,幸好这个规则是可以配置的,下面会教)

prettier index.ts --write

加上 --write,它会直接修改 index.ts 的内容。

VS Code Prettier 插件

Command-line 的用法不方便,通常 Prettier 都是搭配 IDE 用的,在我们每一次保存文件时,自动跑一次 formatting。

首先安装插件

配置 VS Code

{
"[typescript]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
},
}

针对 typescript 文件, 开启保存时自动 format,同时配置 format 时采用 Prettier 插件。(你也可以放全局,不需要针对 TypeScript,因为 Prettier 支持非常多语言)

Config Prettier

Prettier 能配置的东西不多,但还是有几个常用的。

创建 .prettierrc.json5 (注意:它开头有一个点,如果要支持 JSON with Comments 的话,extension 是 .json5,不需要 comment 就 .json 就够了)

.json5 VS Code 也需要配置

{
"files.associations": {
"*.json": "jsonc", // 所有 .json 都是 JSON with Comments
".prettierrc.json5": "jsonc" // .prettierrc.json5 是 JSON with Comments
},
}

然后 .prettierrc.json5 的内容是

{
"overrides": [
{
"files": "*.(ts|js)",
"options": {
"singleQuote": true, // Prettier 默认是 double quote,我改成 single quote
"printWidth": 100, // Prettier 默认最长的代码是 80px width (超出就会换行),我改成 100。
"arrowParens": "avoid", // (value) => value 去掉不必要的括弧 value => value
"endOfLine": "auto" // 这个为了解决 LF,CRLF,\r, \r\n 的兼容问题。
}
}
]
}

针对 .ts 和 .js 配置。

Prettier plugin sort imports

prettier-plugin-sort-imports 插件可以排序 TypeScript 的 import,这样 import 就不会很乱了。

安装

yarn add prettier --dev
yarn add --dev @ianvs/prettier-plugin-sort-imports

提醒:

它有 2 个版本,@trivago 是正版,@ianvs 是 fork 的版本,主要的区别是 @trivago 的正版会排序 CSS import,

而我的项目 CSS 是有 override 概念的,不可以乱排序,所以我用了 @ianvs 的版本,这个版本就不会排序有 side-effect 的 imports。

然后添加配置到 .prettierrc.json5

{
"overrides": [
{
"files": "*.(ts|js)",
"options": {
"singleQuote": true, // Prettier 默认是 double quote,我改成 single quote
"printWidth": 100, // Prettier 默认最长的代码是 80px width (超出就会换行),我改成 100。
"arrowParens": "avoid", // (value) => value 去掉不必要的括弧 value => value
"endOfLine": "auto", // 这个为了解决 LF,CRLF,\r, \r\n 的兼容问题。 // 排序 TypeScript 的 imports 相关配置
"importOrder": [ // 用正则表达式来匹配路径,然后按 array 的顺序排
"<THIRD_PARTY_MODULES>", // match 所有 node_modules 的 imports
"src/module", // match 项目 module
"Shared/Component/Stooges",
"Shared/Component",
"^[.]"
],
"importOrderSortSpecifiers": true, // import { a, b } 内容要不要也排序
"plugins": ["@ianvs/prettier-plugin-sort-imports"]
}
}
]
}

当遇到 side-effiect import,排序就会停止了

所以 Best Practice 是把有 side-effect 的 import 和没有的分开 2 个 group,有 side-effect 的全部在最下面。

另外,文档中有一个把 css 放到最下面的配置

这个配置支队 import styles from 'xx.css' 有效,对 import 'xx.css' 是无效的,因为后者属于有 side-effect。

还有一个小区别,importOrderSeparation options 没有了。原因是 @ianvs 版本更灵活。

ESLint

Command-line

全局安装 eslint package

npm install eslint --global

创建项目

yarn init

添加 TypeScript

yarn add typescript --dev
tsc --init

添加一个 index.ts

const a = '';
const b = "";
const yes = null == undefined;

我故意同时用了 single quote 和 double quote,而且还用了不安全的 ==(JS best practice 是用 === 而不是 ==)

待会儿我们看看 ESLint 能检查出问题吗。

添加 eslint

yarn add eslint --dev

init eslint

yarn create @eslint/config

注:eslint v9.0 有个大改版,v9 之前 init eslint command 是 eslint --init,我们这里用的是 v9 之后的新版本。

这时它会问一些相关的问题。

尝试检查

// 指定检查 index.ts
yarn eslint index.ts // 指定检查所有 .ts 文件
yarn eslint *.ts

效果

error 就表示代码不过关,需要我们修改。

我们可以使用 --fix 自动修复功能

yarn eslint index.ts --fix

不过它的能力有限,只能修复一些初级的代码问题,复杂的依然需要我们自己修改。

VS Code ESLint 插件

安装 VS Code ESLint 插件(微软推出的哦)

现在 index.ts 会出现各种 error 和 warning。

通过 Quick Fix 我们可以查看报错的原因,也可以通过注释 disable 掉这行代码的检测。

通过配置 VS Code 的 codeActionsOnSave 还可以让 VS Code 在保存时自动替我们运行 yarn eslint index.ts --fix。

"[typescript]": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
}
}

Config ESLint & 结合 Prettier

上面我们使用的是 eslint recommended 的代码规范。

市场上还有其它的规范,比如 Google 的、Airbnb 的等等。当然我们也可以自己写规范,或者 override 它们的规范。(ESLint 可以 override 很多配置,不像 Prettier 就只有几个可以配置)

下面是我的规范 eslint.config.mjs

import pluginJs from '@eslint/js';
import globals from 'globals';
import tseslint from 'typescript-eslint'; export default [
{ files: ['**/*.{js,mjs,cjs,ts}'] },
{ languageOptions: { globals: globals.browser } }, pluginJs.configs.recommended, ...tseslint.configs.strict, // 取代 tseslint.configs.recommended
...tseslint.configs.stylistic, // 取代 tseslint.configs.recommended
{
rules: {
'@typescript-eslint/no-non-null-assertion': 'off', // 允许使用 TypeScript 的 Non-null assertion operator
'@typescript-eslint/no-empty-function': 'warn', // 当函数没有内容时会警示
// 当 unused 警惕时,可以用 underscore by pass
'@typescript-eslint/no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
},
],
'@typescript-eslint/no-unused-expressions': [
'error',
{
allowTernary: true, // 允许 ternary expressions call function. e.g. true ? fn1() : fn2();
allowShortCircuit: true, // 允许 true && fn();
},
], '@typescript-eslint/unified-signatures': 'off', // 允许 overload function 'require-await': 'error', // async 函数内一定要有 await
eqeqeq: ['error', 'always', { null: 'ignore' }], // 强制用 === 而不是 ==, 除了 == null 是允许的
'no-constant-condition': ['error', { checkLoops: false }], // 不允许 if(true),但是 white(true) 可以
'no-useless-rename': ['error'], // const { width: width } = dimension <-- 报错.对象解构时 rename 一定要真的换名字 width: width 等于没有丫
'object-shorthand': ['error'], // const { width: width } <-- 报错, variable name same as object key name is not necessary
'no-restricted-globals': [
// 不允许直接用 global,必须加上 prefix window.setTimeout 这样。
'error',
'localStorage',
'location',
'alert',
'setTimeout',
'clearTimeout',
'setInterval',
'clearInterval',
'requestAnimationFrame',
'cancelAnimationFrame',
'navigator',
],
},
},
];

另外,ESLint 还可以结合 Prettier 来使用。这个结合需要特别解释一下,不然会有点乱。

有 2 种结合方式:

  1. 分开用,但是配合执行

    我们项目先添加 Prettier (依据上面我教的方式),然后再添加 ESLint。

    需要特别注意 formatting 的规则一定要一致。比如说,Prettier format 时用 double quote,如果 ESLint 检测时要求 single quote,那肯定是报错的。

    确保双方规则一致后,运行 2 个 commands 就可以了。

    prettier index.ts --write
    yarn eslint index.ts --fix

    配合 VS Code 插件,它会在 save 的时候跑 eslint --fix 然后再跑 prettier --write。(注:它是先跑 eslint --fix 哦)

  2. 把 Prettier 内置到 ESLint 里

    这样的好处是我们只需要运行 1 个 command 就可以了。

    安装额外的插件

    yarn add prettier --dev
    yarn add eslint-config-prettier --dev
    yarn add eslint-plugin-prettier --dev

    然后配置

    接着再加上我们自定义的 prettier rules

当内置 Prettier 之后,其实我们就不需要原本的 Prettier 了。

可以把 on save prettier formatting 关掉。

"[typescript]": {
"editor.formatOnSave": false, // off prettier formatting
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit", // 它里面包含 prettier formatting 了
}
}

有几个点要注意一下

  1. error message 没有那么清楚。

    本来 ESLint 的 formatting error 是很清楚的。

    改成 Prettier 的 formatting 后 error message 被弱化了。

    这是因为 ESLint 有检测的概念,它的 formatting 是先检测哪里有问题,并且给予 error 然后才 --fix。

    Prettier 它没有检测的功能,它是直接 format 输出 formatted 的内容。所有 ESLint 内部是拿 format 前和 format 后的内容做对比,然后返回一个简单的 erorr message。

  2. 现在运行 yarn eslint --fix,它内部会执行 prettier --write。

  3. ESLint 的 Prettier 需要通过在 eslint.config.mjs 里做配置。它可不理 .prettierrc.json 哦。

Stylelint

Stylelint 和 ESLint 大同小异,它是负责检测 CSS / Sass 的。

Command-line

首先全局安装 stylelint package

npm install stylelint --global

创建项目

yarn init

添加一个 index.scss

body {
background-color: #ff0000;
display: flex;
}

添加 stylelint

yarn add stylelint --dev

init stylelint

yarn create stylelint

它会创建一个 .stylelintrc.json 的配置文件。此时已经可以检测 CSS 了,但还不能检测 Sass。我们需要再添加一些配置。

yarn add stylelint-config-standard-scss --dev

它依赖 postcss。

安装 postcss

yarn add postcss@^8.4.19 --dev

然后换掉 extends

运行检测

stylelint index.scss

效果

成功报错了。它同样支持用 --fix 自动修复。

VSCode Stylelint 插件

安装 VS Code ESLint 插件

比起 ESLint 它需要配置比较多东西,

{
"css.validate": false,
"scss.validate": false,
"stylelint.validate": ["css", "scss"],
"[scss]": {
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": "explicit"
}
}
}

先关闭 VS Code 原生对 CSS 和 Sass 的检测,改用 Stylelint

同时添加多一个 fixAll.stylelint 到 codeActionsOnSave

这时就可以看到 error 了

save and --fix 的效果

结合 prettier

yarn add prettier --dev
yarn add stylelint-prettier --dev

修改 .stylelintrc.json(注:它不支持 JSON with Comments)

{
"extends": [
"stylelint-config-standard-scss",
"stylelint-prettier/recommended"
],
"rules": {
"declaration-empty-line-before": null,
"prettier/prettier": [
true,
{
"singleQuote": true,
"printWidth": 100,
"endOfLine": "auto"
}
]
}
}

关闭 VS Code setting [scss] formatOnSave

"[scss]": {
"editor.formatOnSave": false, // off prettier formatting
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": "explicit" // 已经包含 prettier formatting 了
}
}

效果

CSS Properties Ordering

有时候 CSS 属性的顺序很烦人,如果我们想要统一规范可以借助 stylelint-order 插件

yarn add stylelint-order --dev

修改 .stylelintrc.json

properties-order 我们可以放我们规范的顺序。

当然我们也可以跟随市场的规范,比如 Bootstrap 的顺序插件是 stylelint-config-recess-order

yarn add stylelint-config-recess-order

配置

添加 extends : stylelint-config-recess-order 就可以了。stylelint-order plugin 可以移除。

我的 .stylelintrc.json

{
"extends": [
"stylelint-config-standard-scss",
"stylelint-prettier/recommended"
],
"rules": {
// by default class 只能是 kebab-case,要支持 BEM 就用下面这个正则
"selector-class-pattern": [
"^[a-z]+(-?[a-z0-9]+)*(__[a-z0-9]+(-?[a-z0-9]+)?)*(--[a-z0-9]+(-?[a-z0-9]+)?)*$",
{
"resolveNestedSelectors": true
}
],
"scss/dollar-variable-pattern": "^_?[a-zA-Z0-9\\-]+$", // kebab-case 或 _kebab-case
// 因为 Prettier format 会导致这个 error. 相关 Issue:
// https://github.com/prettier/prettier-eslint/issues/186
// https://github.com/prettier/prettier/issues/3806
"scss/operator-no-newline-after": null,
// 空行可以帮助将代码分组,提高阅读体验
"declaration-empty-line-before": null,
// 允许重复 selector,因为有时候我是按功能 group properties 的。
"no-duplicate-selectors": null,
// 我的规范,组件一定是 .html, .css, .ts 三剑客的,方便以后内部扩展功能,不用修改外部接口.
"no-empty-source": null,
"custom-property-pattern": "^_?[a-zA-Z0-9\\-]+$|^[a-zA-Z0-9\\-]+_[a-zA-Z0-9\\-]+$", // kebab-case 或 _kebab-case 或 kebab-case_kebab-case (underscore 前面可以放 namespace 做管理)
// 它老是乱报错。干脆关了吧。它经常搞错的原因如下
// https://stylelint.io/user-guide/rules/no-descending-specificity/#:~:text=However%2C%20since%20the%20linter%20does%20not%20have%20access%20to%20the%20DOM%20it%20can%20not%20evaluate%20this
"no-descending-specificity": null,
"prettier/prettier": [
true,
{
"singleQuote": true,
"printWidth": 100,
"endOfLine": "auto"
}
]
}
}

Work with Web Bundlers (e.g. Webpack, Vite, Rollup)

上面例子中,我们都是以 Command-line 或 VS Code Plugin 的形式去使用 Pretter, ESLint, Stylelint。

还有一种方式是配合 Web Bundlers (e.g. Webpack),当 bundler 打包文件的时候,它会自动跑 eslint --fix 和 stylelint --fix。

对 Webpack 配置 ESLint 和 StyleLint 感兴趣的朋友可以看这篇 Webpack 学习笔记

如果 bundler 不支持 (比如 Angular 的 CLI 对 Stylelint 支持不友好),那就只能在打包之前自己跑 Command-line 了。

分享我的做法:

VS Code Plugin 是一定要用的,因为它可以在 on save 的时候就做 prettier --write,eslint --fix 和 stylelint --fix,立竿见影。

VS Code setting:

所有文件都用 Prettier做 formatting

"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",

有例外的话就特别声明

"[cshtml]": {
"editor.formatOnSave": false,
},

Scss 就用 Stylelint 就好,因为 Stylelint 已经包含了 Prettier。

"[scss]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": "explicit"
}
},

TypeScript 就用 ESLint 就好,因为 ESLint 已经包含了 Prettier。

"[typescript]": {
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
}
},

VS Code 只能在 on save 的时候做 formatting 和检测,这是不够的,我们依然需要一个可以对整个项目做检测的方案。

最好是使用 Command-line,在 git commit 之前可以做个检测:

  1. ESLint

    在 eslint.config.mjs 添加 ignores 属性,表示这些路径不要检测

    然后运行

    yarn eslint **/*.ts **/*.js --fix
  2. StyleLint

    创建一个 .stylelintignore 文件

    node_modules/**
    .yarn/**
    wwwroot/assets/**
    dist/**

    然后运行

    stylelint **/*.scss **/*.css --fix
  3. 或者在 package.json

    "scripts": {
    "lint": "eslint **/*.ts --fix && stylelint **/*.scss --fix"
    // 如果上面这句报错 spawn ENAMETOOLONG,可以是试试下面这句
    // "lint": "eslint '**/*.ts' --fix && stylelint '**/*.scss' --fix"
    },

    运行

    yarn run lint

或者如果项目使用 Web Bundler 而且它支持 ESLint 和 StyleLint 也可以交由 Bundler 做。这样在发布或本地运行前可以做个检测,试试确保代码整齐干净。

使用 Yarn PnP

上面的例子都是用 Yarn Classic。但其实 Prettier、ESLint、Stylelint 都支持 Yarn PnP。只有 2 点要注意

  1. Command 要前面要加 yarn

    eslint index.ts
    // 改成
    yarn eslint index.ts
  2. Prettier 需要 node_modules folder,当我们运行 command

    yarn prettier index.ts

    它会自动创建 folder,但只是空 folder 哦。

总结

要控制 TS、JS、Sass、CSS 的代码质量就必须使用 Prettier、ESLint、Stylelint。

工具 – Prettier、ESLint、Stylelint的更多相关文章

  1. JS代码风格自动规整工具Prettier

    问题背景 通常使用 ESLint做代码风格检查检查, 和部分代码质量检查. 但是使用ESLint在入库时候, 会产生很多的代码修正工作, 需要开发者一个一个的修改. 如果很多,并且时间紧迫,甚是尴尬. ...

  2. vscode 开发项目, Prettier ESLint的配置全攻略(基础篇)

    我们在做项目尤其是多人合作开发的时候经常会因为不同的开发规范和代码风格导致出现冲突, 为了能统一代码风格和规范我们需要使用到prettier和eslint,接下来就一vscode编辑器为例详细讲解下: ...

  3. 前端工具-定制ESLint 插件以及了解ESLint的运行原理

    这篇文章目的是介绍如何创建一个ESLint插件和创建一个ESLint rule,用以帮助我们更深入的理解ESLint的运行原理,并且在有必要时可以根据需求创建出一个完美满足自己需求的Lint规则. 插 ...

  4. 代码风格统一工具:EditorConfig 和 静态代码检查工具:ESLint

    EditorConfig 最常见的用途是:统一文件的编码字符集以及缩进风格 使用 Eslint 做代码 lint,那么为什么还要使用 .editorconfig 呢?细细想了下,应该有两个方面吧. E ...

  5. vscode中eslint插件的配置-prettier

    用vue-cli构建vue项目,会有个eslint代码检测的安装 可vscode自带代码格式化是prettier格式(右键有格式化文件或alt+shift+f) 这时候要在vscode上装一个esli ...

  6. vscode如何配置ts的lint,如何配置才能让eslint和prettier不冲突一键格式化代码(vue开发使用)

    最近在使用ts,发觉tslint在vscode上使用很不方便,不如eslint一键格式化高效,就想着能不能配置下vscode让其像写js一样爽 这篇文章主要解决2个问题,第一个是如何让vscode使用 ...

  7. 一款超人气代码格式化工具prettier

    一.prettier 介绍 官方自己介绍说,prettier是一款强势武断的代码格式化工具,它几乎移除了编辑器本身所有的对代码的操作格式,然后重新显示.就是为了让所有用这套规则的人有完全相同的代码.在 ...

  8. Prettier格式化配置

    HTML/CSS/JS/LESS 文件的 prettier 格式化规则 { // 使能每一种语言默认格式化规则 "[html]": { "editor.defaultFo ...

  9. VS Code官方插件集与工具

    如果您也使用VS Code作为CabloyJS项目开发的主编辑器,那么可以参考官方使用的插件集,此外也提供了一些周边工具 这是官方亲测可用的最简插件集,再也不必东奔西走了 插件集 插件名称 用途 Vi ...

  10. ESLint的使用笔记

    原文地址:https://csspod.com/getting-started-with-eslint/?utm_source=tuicool&utm_medium=referral 在团队协 ...

随机推荐

  1. python 列表append和 的区别??

    python列表中的合并 python列表中append方法是给列表增加一个元素,而'+='是增加上该符号后边的元素,类似于extend方法 不知道对错,先记下来.我学的append方法是在列表最后追 ...

  2. OpenGL 4.0中数据缓冲VBO,VAO,EBO的使用总结

    Opengl是大家常用的一个API,我们用它绘制数据的时候需要使用vao,vbo,ebo等对象,绘制方式分为 vao绘制,ebo绘制等.使用不同api还能分为普通调用以及Instance绘制. 首先申 ...

  3. 老旧 Linux 系统搭建现代 C++ 开发环境 —— 基于 neovim

    问题背景 公司配发的电脑是 macOS,日常开发需要访问 Linux 虚拟机,出于安全方面的考虑,只能通过跳板机登录.这阻止了大多数远程图形界面的使用,让写代码的工作变得复杂起来,市面上非常好用的 V ...

  4. 关于在windows系统下使用Linux子系统

    今天意外刷到一个短视频,介绍了如何在windows下方便的使用系统自带的Linux子系统,本人抱着好奇的心理,也因为最近碰到了只使用windows操作系统解决不了的问题,还有想到以后测试项目大概率也要 ...

  5. 【Java】Input,Output,Stream I/O流 03 系统标准流 & 打印流

    Standard Input,Output Stream 标准输入输出流 - System.in 系统标准输入流 所属InputStream Scanner(System.in); 默认从键盘获取输入 ...

  6. 【微信小程序】02 常用标签组件

    轮播标签: 轮播图 <swiper> <!-- 轮播项 --> <swiper-item>1</swiper-item> <swiper-item ...

  7. 【Scala】05 对象特性Part2

    特质重复继承关系 父类特质 A 子类特质B 继承 A 子类特质C 继承A 类D 继承了 B 又实现了 C class D extends B with C 继承顺序是 D 继承 C 继承 B 继承 A ...

  8. 【JS】02 基础语法

    JS的引入方式: 第一种: 就是我们在HTML标签中使用script标签,然后在这个标签中可以书写JS代码 type="text/javascript"  可以不用写,浏览器会根据 ...

  9. npm WARN config global `--global`, `--local` are deprecated. Use `--location 的解决方法

    1.背景 2.解决步骤 2.1.找到nodejs的安装路径 2.2.修改配置文件 将文件里的 prefix-g 改为 prefix --location=global 修改前: 修改后: 点击保存就解 ...

  10. 构建无服务器数仓(二)Apache DolphinScheduler 集成以及 LOB 粒度资源消费分析

    引言 在数据驱动的世界中,企业正在寻求可靠且高性能的解决方案来管理其不断增长的数据需求.本系列博客从一个重视数据安全和合规性的 B2C 金融科技客户的角度来讨论云上云下混合部署的情况下如何利用亚马逊云 ...