(一)创建一个react项目
用官方脚手架创建项目 再在次基础上添加东西
# 用react脚手架 create-react-app
# 下载项目并安装
npx create-react-app my-app
或
npm init react-app my-app
或
yarn create react-app my-app
# 无论以何种方式下载安装都可以用yarn start或 npm start启动项目
用ts时 可以用 npx create-react-app my-app --typescript,这里我用的时前者,手动添加ts
(二)、引入ts
yarn add typescript
# 添加 tsconfig.json !!!
然后把js文件改为tsx,重新启动项目,根据需要添加给现有的模块添加ts声明文件模块@types
tsconfig.ts tsconfig.json 如果一个目录下有tsconfig.json文件,那么这个目录就是ts项目的根目录。tsconfig.json中指定了用来编译这个项目的根文件和编译选项。IED,tsc和ts-loader共用这一份文件
使用tsconfig.json
# ts 编译配置文件 规定了编译是ts入口,编译哪些文件、哪些类型的文件、生成什么类型的文件 等等。
# tsconfig.json文件可以是个空文件,那么所有默认的文件(如上面所述)都会以默认配置选项编译。
# 常用配置
{
"compilerOptions": {
"target": "ES5", // 目标语言的版本
"module": "commonjs", // 指定生成代码的模板标准
"noImplicitAny": true, // 不允许隐式的 any 类型
"removeComments": true, // 删除注释
"preserveConstEnums": true, // 保留 const 和 enum 声明
"sourceMap": true // 生成目标文件的sourceMap文件
"incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度
"tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
"diagnostics": true, // 打印诊断信息
"outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD",
"lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array",
"allowJS": true, // 允许编译器编译JS,JSX文件
"checkJs": true, // 允许在JS文件中报错,通常与allowJS一起使用
"outDir": "./dist", // 指定输出目录
"rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
"declaration": true, // 生成声明文件,开启后会自动生成声明文件
"declarationDir": "./file", // 指定生成声明文件存放目录
"emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件
"inlineSourceMap": true, // 生成目标文件的inline SourceMap,inline SourceMap会包含在生成的js文件中
"declarationMap": true, // 为声明文件生成sourceMap
"typeRoots": [], // 声明文件目录,默认时node_modules/@types
"types": [], // 加载的声明文件包
"noEmit": true, // 不输出文件,即编译后不会生成任何js文件
"noEmitOnError": true, // 发送错误时不输出任何文件
"noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用
"importHelpers": true, // 通过tslib引入helper函数,文件必须是模块
"downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现
"strict": true, // 开启所有严格的类型检查
"alwaysStrict": true, // 在代码中注入'use strict'
"strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
"strictFunctionTypes": true, // 不允许函数参数双向协变
"strictPropertyInitialization": true, // 类的实例属性必须初始化
"strictBindCallApply": true, // 严格的bind/call/apply检查
"noImplicitThis": true, // 不允许this有隐式的any类型
"noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错)
"noUnusedParameters": true, // 检查未使用的函数参数(只提示不报错)
"noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
"noImplicitReturns": true, //每个分支都会有返回值
"esModuleInterop": true, // 允许export=导出,由import from 导入
"allowUmdGlobalAccess": true, // 允许在模块中全局变量的方式访问umd模块
"moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略,即相对的方式导入
"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
"paths": { // 路径映射,相对于baseUrl
// 如使用jq时不想使用默认版本,而需要手动指定版本,可进行如下配置
"jquery": ["node_modules/jquery/dist/jquery.min.js"]
},
"rootDirs": ["src","out"], // 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化,这也设置可以虚拟src和out在同一个目录下,不用再去改变路径也不会报错
"listEmittedFiles": true, // 打印输出文件
"listFiles": true// 打印编译的文件(包括引用的声明文件)
},
"files": [ // 指定待编译文件
"./src/index.ts"
],
"compileOnSave": false, //设置编辑器保存文件的时候自动编译
"exclude": [ //指定编译器需要排除的文件或文件夹。默认排除 node_modules 文件夹下文件。
"src/lib" // 排除src目录下的lib文件夹下的文件不会编译
],
// 引入其他ts配置文件,继承配置。默认包含当前目录和子目录下所有 TypeScript 文件。
"extends": "./tsconfig.base.json"// 把基础配置抽离成tsconfig.base.json文件,然后引入
// 指定需要编译的单个文件列表
"files": [
// 指定编译文件是src目录下的leo.ts文件
"scr/leo.ts"
]
// 指定编译需要编译的文件或目录
"include": [
// "scr" // 会编译src目录下的所有文件,包括子目录
// "scr/*" // 只会编译scr一级目录下的文件
"scr/*/*" // 只会编译scr二级目录下的文件
]
// 指定工程引用依赖。在项目开发中,有时候我们为了方便将前端项目和后端node项目放在同一个目录下开发,两个项目依赖同一个配置文件和通用文件,但我们希望前后端项目进行灵活的分别打包
"references": [ // 指定依赖的工程
{"path": "./common"}
]
// 设置自动引入库类型定义文件(.d.ts)相关。
包含 3 个子属性:
enable : 布尔类型,是否开启自动引入库类型定义文件(.d.ts),默认为 false;
include : 数组类型,允许自动引入的库名,如:[“jquery”, “lodash”];
exculde : 数组类型,排除的库名。
"typeAcquisition": {
"enable": false,
"exclude": ["jquery"],
"include": ["jest"]
}
}
不带任何输入文件的情况下调用tsc,编译器会从当前目录开始去查找tsconfig.json文件,逐级向上搜索父目录。 使用命令行参数--project(或-p)指定一个包含tsconfig.json文件的目录。
当命令行上指定了输入文件时,tsconfig.json文件会被忽略。
(三)项目中的 webpack.config.js配置
create-react-app 中用了 babel-loader 使其能够处理 TypeScript 代码,这里主要在 rules 中添加 ts-loader,ts-loader内部源码调用了ts编译器(即tsc)。
const path = require('path');
module.exports = {
entry: './src/index.ts',
devtool: 'inline-source-map',//想要启用 source map,我们必须配置 TypeScript,以将内联的 source map 输出到编译后的 JavaScript 文件中。然后配置 webpack.config.js 文件,让 webpack 提取 source map,并内联到最终的 bundle 中
module: {
rules: [
{
test: /\.tsx?$/,
use: [{
loader: 'ts-loader',
option: {
// 开启时:编译器仅做语言转换不做类型检查,错误的类型赋值依然会触发IDE报错,但不会阻止编译
transpileOnly: false
}
}],
exclude: /node_modules/
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
eslint
代码规范检查 官方脚手架生成的项目中的eslint-config-react-app支持es代码检查,但有ts代码检查规则但没启用,需要在vscode中配置一下,才支持ts代码检查
跟着项目走的vscode setting 项目里新建文件夹.vscode/setting.json
{
"eslint.validate": [
"javascript",
"javascriptreact"
]
}
eslint npm包
用于代码检查,webpack使用,是一个loader对一些文件编译的时候进行规则检查,如果出错会在编译时控制台报错,或者暂停编译
npm install eslint --save-dev
eslint --init
生成 .eslintrc.json 文件 ,eslint读这个文件的规则 编译文件
{
"env":{
"browser":true,//浏览器环境
"node":true,//Node环境
"es6":true,//es6语法
"commonjs":true,//commonjs
"worker":true//webwork相关语法
},
"globals":{
"Atomics":"readonly",
"SharedArrayBuffer":"readonly"
},
// 可以配置解析器,默认是用的typescript的解析器,
"parser": "@typescript-eslint/parser”,
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "single"],
"no-console":1
},
// 它提供的继承功能直接集成了一些默认的配置
"extends":[
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended"
],
// 加各种插件,比如你想增加React的检查怎么办?你需要安装eslint-plugin-react这个插件,然后在配置中增加以下内容
"plugins":["react”]
}
配置文件讲解 按照上述操作,会生成默认 .eslintrc.js 配置文件,内容如下:
// .eslintrc.js
module.exports = {
"env": {
"browser": true,
"commonjs": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
"jsx": true
},
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"windows"
],
"quotes": [
"error",
"double"
],
"semi": [
"error",
"always"
]
}
}
该文件导出一个对象,对象包含属性 env、extends、parserOptions、plugins、rules 五个属性,作为刚学习 Eslint 的新手,我们总是想要竭尽所能的详细了解每一个属性是什么,干嘛用的,以获取小小的安全感。
env、parserOptions、plugins 这三个放在一起将是因为你只需要知道它们是干嘛的:我的程序里要用到 ES6 、React 、JSX 语法,这几个属性就是让 Eslint 能够检验到这些语法的。其余的你不需要知道更多的哪怕一丢丢的东东了。
作者在学习之初在这块浪费了很多时间,官方文档看了很多遍,大多不能理解什么意思,后来想它既然提供这么一个自动生成配置文件的工具,并且是命令行交互的方式,我只需要告诉它我要用 ES6 、React 、JSX 语法,它会自动进行相关配置满足我的要求即可。
extends 前面一直说检验代码遵循编码规范,那到底是什么规范呢。
值为 "eslint:recommended" 的 extends 属性启用一系列核心规则,这些规则是经过前人验证的最佳实践(所谓最佳实践,就是大家伙都觉得应该遵循的编码规范),想知道最佳实践具体有哪些编码规范,可以在 eslint规则表 中查看被标记为 √ 的规则项。
如果觉得官方提供的默认规则不好用,可以自定义规则配置文件,然后发布成 Npm 包,eslint-config-airbnb 就是别人自定义的编码规范,使用 npm 安装后,在我们自己的 .eslintrc.js 中进行配置 "extends": "airbnb",eslint-config 这个前缀可以省略不写,这样我们就使用了 eslint-config-airbnb 中的规则,而不是官方的规则 "extends":"eslint:recommended" 了。关于如何创建自定义规则配置并共享可以参考: 如何自定义规则配置
关于 "airbnb" 编码规范说两句,在接触到大多数开源项目中,大多数的作者都会使用 "airbnb" 编码规范而不是 官方的 "extends": "eslint:recommended" 编码规范。
如果我们觉得 eslint-config-airbnb 规则配置中个别规则并不符合当前项目的要求,可以直接在 .eslintrc.js 配置 rules 属性,优先级高于共享规则 airbnb。
rules 配置文件也生成了,我们怎么知道我们的系统会遵循什么规则呢??
在前面的列子中,使用 npm run lint 校验出了三处错误,假如我们的项目中字符串就是要使用单引号而不是双引号,代码结尾就是要不加分号才好看,变量就是定义了可能不会使用,我们可以通过设置 rules 来定义我们自己的编码规范,即规则。
ESLint 附带有大量的规则,修改规则应遵循如下要求:
"off" 或 0 - 关闭规则 "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出) "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出) 有的规则没有属性,只需控制是开启还是关闭,像这样:"eqeqeq": "off",有的规则有自己的属性,使用起来像这样:"quotes": ["error", "double"],具体有没有自带属性,可查看 eslint规则表。
修改 .eslintrc.js 文件中的 rules 属性:
"rules": {
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"windows"
],
"quotes": [
"error",
"single" // 改成字符串必须由单引号括起来而不是双引号,'string'不报错,"string"报错
],
"semi": [
"error",
"never" // 改成代码结尾不再加分号,加了分号报错,不加分号不报错
],
"no-unused-vars": 0 // 0 相当于 off,表示关闭规则,相当于不再校验这条规则:变量定义了必须使用
}
此时再使用 npm run lint 进行代码校验,没有报错就说明校验通过,代码符合统一编码规范。
eslint vscode 插件
用于代码检查,vscode使用,在编码的过程中对一些文件的代码规则进行检测,如果出错会在代码界面上提示出错,方便开发人员查看 在vscode编辑器的setting.json文件中添加 "eslint.autoFixOnSave": true,
{
// #每次保存的时候自动格式化
"editor.formatOnSave": true,
// #每次保存的时候将代码按eslint格式进行修复 读eslint规则配置文件
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": ["javascript", "javascriptreact"],
// vscode默认启用了根据文件类型自动设置tabsize的选项
"editor.detectIndentation": false,
// 重新设定tabsize
"editor.tabSize": 2,
// #让函数(名)和后面的括号之间加个空格
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
"window.zoomLevel": 0,
"explorer.confirmDelete": false,
"explorer.confirmDragAndDrop": false,
"editor.renderControlCharacters": true,
"editor.renderWhitespace": "all",
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
tslint 已经停止维护,用eslint吧
Prettier
代码格式化工具 ,强制使用prettier的规则进行代码格式化
Prettier npm包 .prettierrc.json 但是很少人会用命令行,都是用IDE,通过IDE和prttier的整合直接代码格式化
mkdir learn-prettier && cd learn-prettier
yarn init
yarn add prettier --dev --exact
// 在learn-prettier/src目录下创建index.js文件,然后自己写一些JS代码。JS代码用上文那个超长的foo(......)就可以,自己也可以改的更乱一些,但必须符合JS语法。
yarn prettier --write src/index.js
// 在看格式化之后的index.js,已经重新输出成固定格式了。
// 一次格式化所有代码
yarn prettier --write './src/**/*.js' './src/**/*.jsx’
prettier vscode插件 安装后 setting.json
// 让prettier使用eslint的代码格式进行校验
"prettier.eslintIntegration": true,
"prettier.semi": false, #去掉代码结尾的分号
"prettier.singleQuote": true, #使用带引号替代双引号
Prettier 反复强调自己是一个 Opinionated code formatter,而且只有 few(很少) options。这意味着:
Prettier 不是一个你想如何设置就如何设置的代码风格格式化工具,不能任由你改变其输出风格。其最主要的目的就是让团队停止争吵,配置项越多,就离这个主要目的越远,团队就会一直讨论应该如何配置。这就是 Prettier 的哲学
prettier 和 Linters 的整合需要做两件事:
禁用 Linters 自己的 Formatting rules,让 Prettier 接管这些职责。这些配置有现成的 Config,Linters 的配置继承这个 Config 就可以了。 让 Linters 执行时首先能够调用 Prettier 格式化,然后再检查 Code-quality 类规则。这是 由 Linters 的 Plugin 实现的。
vue项目配置规则并且保存自动格式化代码
1、.eslint.js 配置
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
es6: true,
},
// 官方推荐的格式化规则
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// add your custom rules here
//it is base on https://github.com/vuejs/eslint-config-vue
rules: {
"vue/max-attributes-per-line": [2, {
"singleline": 10,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}],
"vue/singleline-html-element-content-newline": "off",
"vue/multiline-html-element-content-newline":"off",
"vue/name-property-casing": ["error", "PascalCase"],
"vue/no-v-html": "off",
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ["error", "always", {"null": "ignore"}],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
}
2、vscode配置setting.json
{
// #每次保存的时候自动格式化
"editor.formatOnSave": true,
// #每次保存的时候将代码按eslint格式进行修复
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.format.enable": true,
//autoFix默认开启,只需输入字符串数组即可
"eslint.validate": [
"javascript",
"vue",
"html"
],
// #让prettier使用eslint的代码格式进行校验
"prettier.eslintIntegration": true,
// #去掉代码结尾的分号
"prettier.semi": false,
// #使用带引号替代双引号
"prettier.singleQuote": true,
// #让函数(名)和后面的括号之间加个空格
"javascript.format.insertSpaceBeforeFunctionParenthesis": true,
"vetur.format.defaultFormatterOptions": {
// "js-beautify-html": {
// "wrap_attributes": "force-aligned"
// // #vue组件中html代码格式化样式
// }
"prettier": {
// Prettier option here
"trailingComma": "es5", // 多行时,尽可能打印尾随的逗号
"tabWidth": 4, // 会忽略vetur的tabSize配置
"useTabs": false, // 是否利用tab替代空格
"semi": true, // 句尾是否加;
"singleQuote": true, // 使用单引号而不是双引号
"arrowParens": "avoid", // allow paren-less arrow functions 箭头函数的参数使用圆括号
}
}
}
eslint-plugin-vue网站 eslint.vuejs.org/rules/html-…
github上eslint-plugin-vue在vuejs项目下面 github.com/vuejs/eslin…
自动格式化
1、 .eslint.json里写好配置
2、vscode setting里写配置
{
// #每次保存的时候将代码按eslint格式进行修复 读eslint规则配置文件
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
3、vscode编辑器中启用eslint
4、如果要全部格式化所有代码 在package.json里写指令
"lint-fix": "eslint --fix --ext .js --ext .vue src/biz"
然后执行该命令就可以src/biz下的所有js、vue后缀的文件都格式化
5 关闭单个文件的一段代码的eslint检查
多行:
/* eslint-disable */
window.webkit.messageHandlers.jsCallOC.postMessage({name: 'tttt', age: 18, big: true});
/* eslint-enable */
单行:
// eslint-disable-next-line
// eslint-disable-line