theme: channing-cyan
highlight: monokai-sublime
哈喽大家好,我是haibin。这是我写的第一册技术小书,在掘金会分几篇发布,也可以直接点击下面在线访问全册,希望大家喜欢!
小书介绍
前言
以往像我们搭建vue项目,第一时间想到的就是vue-cli直接命令生成脚手架。
这种方式看似非常轻松、方便,平时写写业务代码或许无所谓,但直到需要你优化项目、解决原理层棘手问题的时候你才猛然发现,过于依赖这个工具反而会导致我们对于底层原理一概不知。这个时候就会措手不及,才逐渐开始去了解底层的部分。
与其到时被动,不如现在主动从0到1去搭建vue3脚手架!
这本小书会手把手地教你如何从“空文件夹”搭建到企业级脚手架。
Babel
到这里得开始关注自身代码的需求了,大多数项目最基础也需要使用到ES6语法了。虽然目前有好一部分浏览器都支持,但是难免会有某些不支持的情况,最好的做法全部转成ES5
再给浏览器解析。
我们选择目前非常热门的ES编译器Babel
来进行转换,需要安装@babel/core
和@babel/preset-env
两个插件和创建babel.config.js
配置文件。
npm i -D @babel/core @babel/preset-env
// babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env", // ES
{
targets: {
browsers: ["> 0.25%", "not dead"],
},
},
],
],
};
Babel & Webpack
配置好babel后还需要借助Webpack来对js文件进行构建转换,需要安装babel-loader
来配置。
npm i -D babel-loader
// webpack.base.js
module.exports = {
entry: {
index: path.resolve(__dirname, "../src/index.js"),
},
output: {
path: path.resolve(__dirname, "../dist"),
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
favicon: path.resolve(__dirname, "../public/logo.svg"),
}),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
},
},
],
},
};
这样一来babel-loader
就会自动使用babel.config.js
的配置了,我们添加ES6语法验证一下。
// src/index.js
console.log("hello world!");
const test = 123;
console.log(test);
let a = 1;
const b = 2;
const c = 333;
console.log("result", a, b, c);
console.log([1, 2, 3].map((n) => n + 1)); // 使用ES6箭头函数
接着执行npm run build
看看构建结果
可以看到成功将ES6的箭头函数
转换成ES5的匿名函数
。
Babel & ESLint
前面可以知道我们能够使用哪种版本的ES6语法取决于babel的配置,但有没想过那eslint检查的是哪个版本的ES6语法?
如果版本不一致,可能会导致babel支持
某个ES6语法而eslint不支持
时反而出现报错的情况。
例如下面使用ES2021的语法ESLint就会提示解析错误:
// src/index.js
console.log("hello world!");
const test = 123;
console.log(test);
let a = 1;
const b = 2;
const c = 333;
console.log("result", a, b, c);
console.log([1, 2, 3].map((n) => n + 1));
let d = null;
d ||= "daotin";
console.log(d);
下面我们再看看构建会不会有问题:
npm run build
可以看出来webpack通过babel的配置一样能够转换ES2021的语法,主要原因是在于@babel/preset-env
默认就是支持最新的ES语法。
而ESLint会报错的原因是在于我们配置的是ES6版本的语法,也就是2015的版本。
这个时候可以通过配置es2021
来支持这个版本的语法:
// .eslintrc.js
module.exports = {
env: {
browser: true, // 支持浏览器环境
node: true, // 识别 CommonJS
es2021: true, // 识别 ES 的代码
},
// 继承ESLint的规则集
extends: [
"eslint:recommended", // ESLint自带
"plugin:prettier/recommended" // Prettier
]
};
但是这样还是没办法完全避免版本不一致的问题,最好的方法还是两者使用同一种配置,所以我们需要用到插件@babel/eslint-parser
来解决这个问题。
npm i -D @babel/eslint-parser
// .eslintrc.js
module.exports = {
env: {
browser: true, // 支持浏览器环境
node: true, // 识别 CommonJS
es2021: true, // 识别 ES 的代码
},
// 继承ESLint的规则集
extends: [
"eslint:recommended", // ESLint自带
"plugin:prettier/recommended" // Prettier
],
overrides: [
{
files: ["**/*.{js,jsx}"], // 只处理 js 和 jsx 文件
parser: "@babel/eslint-parser", // 使用 babel 来解析 js 文件
parserOptions: {
sourceType: "module", // 支持 import/export
allowImportExportEverywhere: false,
ecmaFeatures: {
globalReturn: false,
},
babelOptions: {
configFile: './babel.config.js', // 指定babel配置文件
},
},
}
]
};
这样一来就可以用一个babel.config.js
文件来配置Webpack
的构建和ESLint
的代码检查了。
TypeScript
通过前面的babel
配置,终于可以肆意使用最新版的ES语法了。但是如今大部分企业实际上都在使用TypeScript
了,而且对代码的可维护性、壮健性都有很大的提升。
所以我们这里也需要对TypeScript
也做下支持,首先通过命令创建tsconfig.json
配置文件。
# 创建tsconfig.json
npx tsc --init
// 修改tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"baseUrl": "./",
"sourceMap": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"alwaysStrict": true,
"skipLibCheck": true
}
}
创建个TS文件试试:
// src/index.ts
interface Test {
a: number;
b: string;
}
const test: Test = {
a: 111,
b: "111",
};
console.log(test);
结果ESLint这边解析出了问题,那后面我们加上ESLint的检测吧。
TypeScript & ESLint
首先得安装相应的三个插件typescript
、@typescript-eslint/parser
、@typescript-eslint/eslint-plugin
。
npm install -D
typescript # TypeScript
@typescript-eslint/parser # TypeScript 解析器
@typescript-eslint/eslint-plugin # TypeScript 规则集和插件功能
再来修改ESLint配置文件
// .eslintrc.js
module.exports = {
...
overrides: [
...
{
files: ["**/*.{ts,tsx}"], // 只处理 ts 和 tsx 文件
parser: "@typescript-eslint/parser", // 解析 TypeScript
parserOptions: {
project: ["./tsconfig.json"], // 指定ts配置文件
},
extends: [
"plugin:@typescript-eslint/recommended", // 官方语法检查
"plugin:@typescript-eslint/recommended-requiring-type-checking", // 类型检查
],
plugins: ["@typescript-eslint"],
}
]
};
这下你会发现之前src/index.ts
的ESLint报错提示消失了。
TypeScript & Webpack
现在光能用TypeScript
写代码还不行,还得让Webpack
支持TS转JS才行。
之前我们ES6转ES5时是让Webpack
通过Babel
配置来转换,这次TypeScript
也可以通过Babel
配置给Webpack
转换。
npm i -D @babel/preset-typescript
// babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env", // ES
{
targets: {
browsers: ["> 0.25%", "not dead"],
},
},
],
[
"@babel/preset-typescript", // TS
],
],
};
对应的Webpack配置入口
和babel-loader解析后缀
都需要修改。
// webpack.base.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: {
index: path.resolve(__dirname, "../src/index.ts"),
},
output: {
path: path.resolve(__dirname, "../dist"),
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
favicon: path.resolve(__dirname, "../public/logo.svg"),
}),
],
module: {
rules: [
{
test: /\.(js|ts)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
},
},
],
},
};
到这里再去执行npm run build
就会发现构建没有问题了。
前面使用@babel/preset-typescript
进行转换的方式的优点在于构建效率快,但缺点是缺少类型检查。
为了兼容不同的使用人群,这边也介绍下使用ts-loader
的方式,优点是具有类型检查,缺点则是构建效率较慢。
npm i -D ts-loader
// webpack.base.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: {
index: path.resolve(__dirname, "../src/index.ts"),
},
output: {
path: path.resolve(__dirname, "../dist"),
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
favicon: path.resolve(__dirname, "../public/logo.svg"),
}),
],
module: {
rules: [
{
// test: /\.(js|ts)$/,
test: /\.(js)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
},
},
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
configFile: path.resolve(process.cwd(), 'tsconfig.json')
},
},
],
},
};
npm run dev # 构建看看效果
这个时候我们再尝试写下错误的类型,就会看到终端会出现报错信息。
// src/index.ts
interface Test {
a: number;
b: string;
c: string;
}
const test: Test = {
a: 111,
b: "111",
};
console.log(test);
最后总结下,这里我们介绍了两种方式来转换TS:
@babel/preset-typescript
这种方式的好处在于构建效率快,但缺点是缺少类型检查。ts-loader
这种方式的优点是构建时会进行类型检查,但构建效率慢。
具体使用哪种方式来转换TS,就看个人的取舍了,这里不做推荐。
暂无评论内容