现代前端工程化实践:高效构建的秘密
一、前端工程化错误监控
这种监控可以帮助开发人员及时发现和解决问题,提高应用程序的稳定性和可靠性。
1. Sentry:Sentry是一款开源的错误监控平台,可以监控前端、后端以及移动端应用程序中的错误和异常。Sentry提供了实时错误报告、错误分析和错误解决方案等功能。2. Bugsnag:Bugsnag是一款专门用于监控Web应用程序和移动应用程序的错误监控工具。它可以捕获JavaScript异常、网络请求错误、客户端错误等。3. Google Analytics:Google Analytics可以监控网站的访问量、页面浏览量、访问时长和用户行为等。它还提供了实时报告和错误报告等功能,可以帮助开发人员发现和解决问题。4. Performance API:Performance API是一个浏览器提供的API,可以监控Web应用程序的性能。它可以捕获页面加载时间、资源下载时间和JavaScript执行时间等信息。5. 前端错误监控SDK:很多前端错误监控工具都提供了JavaScript SDK,可以通过在应用程序中引入SDK来捕获错误和异常。开发人员可以根据捕获的错误信息来定位和解决问题。
二、项目构建
1、脚手架开局(已废弃⚠️)
全局安装create-react-app:
$ npm install -g create-react-app创建一个项目:
$ create-react-app your-app 注意命名方式Creating a new React app in /dir/your-app.如果不想全局安装,可以直接使用npx:
$ npx create-react-app your-app 也可以实现相同的效果
2、webpack开局(已废弃⚠️)
初始化项目空间
新建一个项目目录,在目录下执行:npm init -y
此时将会生成 package.json 文件
之后新建 src、config(配置webpack)文件夹,新建index.html文件
安装webpack和react相关依赖文件
npm i webpack webpack-cli webpack-dev-server html-webpack-plugin babel-loader path -D
npm i react react-dom
在src目录配置index.js文件
import React from 'react';
import ReactDOM from 'react-dom';ReactDOM.render(<React.StrictMode><div>你好,React-webpack5-template</div></React.StrictMode>,
document.getElementById('root')
);
在src目录配置index.html文件
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>react-app</title></head><body><div id="app"></div></body>
</html>
配置根目录webpack配置文件
新建webpack.common.js文件,部分代码仅供参考
const webpack = require('webpack');
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackObfuscator = require('webpack-obfuscator');
const pages = ['index' /*, "message", */]; // 多页面频道配置
const envConfig = require('./config/env');
const isProduction =process.env.APP_ENV === 'production' ||process.env.APP_ENV === 'preProduction';
const isDevelopment = process.env.APP_ENV === 'development';function recursiveIssuer(m) {if (m.issuer) {return recursiveIssuer(m.issuer);} else if (m.name) {return m.name;} else {return false;}
}// 获取CSS输出
function getCssOutput() {let pathStyle = {};pages.map((item) => {pathStyle[`${item}Styles`] = {name: item,test: (m, c, entry = item) =>m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,chunks: 'all',enforce: true,};});return pathStyle;
}/*** 【获取entry文件入口】* @returns {Object} 返回的entry { "static":"./src/static/index.js",}*/
function getEntry() {let entryConfig = {};pages.map((item) => {entryConfig[item] = `./src/${item}.js`;});return entryConfig;
}// 获取多个页面html生成配置
function getHtmlPlugin() {let plugins = [];pages.map((item) => {plugins.push(new HtmlWebpackPlugin({publicPath: envConfig.STATIC_DOMAIN, // 静态资源引入domaintemplate: `./src/${item}${isProduction ? '_prod' : ''}.html`,filename: `${item}.html`,hash: false,chunks: [item],// favicon: './favicon.ico',inject: true,minify: {collapseWhitespace: true, //把生成文件的内容的没用空格去掉,减少空间},}));});return plugins;
}module.exports = {entry: getEntry(), // 获取entry文件入口optimization: {moduleIds: 'deterministic',chunkIds: 'deterministic',splitChunks: {cacheGroups: getCssOutput(), // CSS输出配置},},output: {filename: 'static/js/[name].bundle.[fullhash].js',chunkFilename: 'static/js/[name].bundle.[chunkhash].js',path: path.resolve(__dirname, 'dist/'),publicPath: envConfig.PUBLIC_PATH,},resolve: {extensions: ['.js', '.json'],alias: {'@/store': path.join(__dirname, 'src/store'),'@/actions': path.join(__dirname, 'src/actions'),'@/reducers': path.join(__dirname, 'src/reducers'),'@/components': path.join(__dirname, 'src/components'),'@/containers': path.join(__dirname, 'src/containers'),'@/assets': path.join(__dirname, 'src/assets'),'@/utils': path.join(__dirname, 'src/utils'),'@/socket': path.join(__dirname, 'src/socket'),'@/reactX': path.join(__dirname, 'src/reactX'),'@/pages': path.join(__dirname, 'src/pages'),'@/img': path.join(__dirname, 'src/assets/img'),'@/hooks': path.join(__dirname, 'src/hooks'),},},module: {rules: [{test: /\.jsx?$/,exclude: /node_modules/,use: {loader: 'babel-loader',},},{test: /\.(le|c)ss$/, // .less and .cssuse: [isDevelopment? 'style-loader': {loader: MiniCssExtractPlugin.loader,options: {publicPath: '../',},},{loader: 'css-loader',options: {// url: false,sourceMap: isDevelopment,},},'less-loader',],},{test: /\.(html|htm)$/i,use: 'html-withimg-loader', // 解析 html中的图片资源},{//图片小于一定大小使用base64 否则使用file-loader产生真实图片test: /\.(png|gif|jp?g|svg|webp|ico)$/,use: [{loader: 'url-loader',options: {limit: 5000, //小于限定使用base64name: 'static/images/[name].[hash:8].[ext]',publicPath: `../../`,esModule: false,},},],},{test: /\.(eot|woff|woff2|ttf|OTF|otf)(\?.*)?$/,use: [{loader: 'file-loader',options: {name: 'static/fonts/[name].[hash:8].[ext]',publicPath: `../../`,esModule: false,},},],},{test: /\.(ogg|mp3|mp4|wav|mpe?g)$/,use: [{loader: 'file-loader',options: {publicPath: `../../`,name: 'static/medias/[name].[hash:8].[ext]',esModule: false,},},],},{test: /\.jsx?$/,include: [path.resolve(__dirname, 'src/pages/allCase/index.js')],enforce: 'post',use: {loader: WebpackObfuscator.loader,options: { rotateStringArray: true },},},],},plugins: [...[new webpack.DefinePlugin({envConfig: JSON.stringify(envConfig),}),new webpack.HotModuleReplacementPlugin(),new CleanWebpackPlugin({cleanOnceBeforeBuildPatterns: !isDevelopment? ['**/*', '!global*', '!client/js/global*', '!client/js/global/**']: [],}), // 清理非global目录文件],...getHtmlPlugin(),],stats: { warnings: false, children: false },
};
新建webpack.base.conf.js文件,部分代码仅供参考
"use strict";
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");module.exports = {// 入口起点entry: {app: "./src/index.js",},// 输出output: {path: path.resolve(__dirname, "../dist"),filename: "[name].js",},// 解析resolve: {extensions: [".ts", ".tsx", ".js", ".json"],alias: {"@components": path.join(__dirname, "../src/components"),"@utils": path.join(__dirname, "../src/utils"),"@pages": path.join(__dirname, "../src/pages"),},},// loadermodule: {rules: [{test: /\.js|jsx$/,exclude: /(node_modules|bower_components)/, // 屏蔽不需要处理的文件(文件夹)(可选)loader: "babel-loader",},{//支持less// npm install style-loader css-loader less-loader less --save-devtest: /\.(le|c)ss$/, // .less and .cssuse: ["style-loader", "css-loader", "less-loader"], // 创建的css文件存在html的头部},],},// 插件plugins: [new HtmlWebpackPlugin({filename: "index.html",template: "src/index.html",inject: "body",hash: false,minify: {collapseWhitespace: true, //把生成文件的内容的没用空格去掉,减少空间},}),],
};
新建webpack.development.js文件,部分代码仅供参考
"use strict";
const { merge } = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");
const path = require("path");
const webpack = require("webpack");module.exports = merge(baseWebpackConfig, {// 模式mode: "development",// 调试工具devtool: "inline-source-map",// 开发服务器devServer: {static: path.resolve(__dirname, "static"),historyApiFallback: true, // 在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.htmlcompress: true, // 启用gzip压缩hot: true, // 模块热更新,取决于HotModuleReplacementPluginhost: "127.0.0.1", // 设置默认监听域名,如果省略,默认为“localhost”port: 8888, // 设置默认监听端口,如果省略,默认为“8080”},optimization: {nodeEnv: "development",},
});
新建webpack.prod.conf.js文件
"use strict";
const { merge } = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");const path = require("path");
const webpack = require("webpack");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");module.exports = merge(baseWebpackConfig, {// 模式mode: "production",// 调试工具devtool: "source-map",// 输出output: {path: path.resolve(__dirname, "../dist"),filename: "js/[name].[chunkhash].js",},// 插件plugins: [new CleanWebpackPlugin()],// 代码分离相关optimization: {nodeEnv: "production",runtimeChunk: {name: "manifest",},splitChunks: {minSize: 30000,minChunks: 1,maxAsyncRequests: 5,maxInitialRequests: 3,name: false,cacheGroups: {vendor: {test: /[\\/]node_modules[\\/]/,name: "vendor",chunks: "initial",},},},},
});
新建.babelrc文件
{"presets": ["latest", "react", "stage-2"],"plugins": []
}
修改package.json中的script代码
"scripts": {"dev": "webpack-dev-server --hot --config config/webpack.dev.conf.js","start": "npm run dev","build": "webpack --progress --colors --config config/webpack.prod.conf.js"},
此时,package.json中部分代码如下
{"name": "webpack-react-demo","version": "1.0.0","description": "","main": "index.js","scripts": {"dev": "webpack-dev-server --hot --config config/webpack.dev.conf.js","start": "npm run dev","build": "webpack --progress --config config/webpack.prod.conf.js"},"license": "ISC","devDependencies": {"babel-core": "^6.26.3","babel-loader": "^7.1.5","babel-plugin-import": "^1.13.5","babel-preset-latest": "^6.24.1","babel-preset-react": "^6.24.1","babel-preset-stage-0": "^6.24.1","clean-webpack-plugin": "^4.0.0","css-loader": "^6.7.1","file-loader": "^6.2.0","html-webpack-plugin": "^5.5.0","less-loader": "^11.0.0","node-less": "^1.0.0","style-loader": "^3.3.1","url-loader": "^4.1.1","webpack": "^5.74.0","webpack-cli": "^4.10.0","webpack-dev-server": "^4.10.1","webpack-merge": "^5.8.0"},"dependencies": {"less": "^4.1.3","react": "^18.2.0","react-dom": "^18.2.0","react-router-dom": "^5.1.2"}
}
在项目中添加代码规范检测
yarn add babel-eslint --save-dev
yarn add @umijs/fabric -D //@umijs/fabric一个包含 prettier,eslint,stylelint 的配置文件合集。
yarn add prettier --save-dev //默认@umijs/fabric已经给我们安装了需要的依赖,但是默认是没有pretter。结合项目中安装eslint-plugin-react-hooks并在.eslintrc.js中配置rules:{"react-hooks/rules-of-hooks":'error',"react-hooks/exhaustive-deps":'warn',}
可以一键生成hooks依赖
新增如下文件(用于规范项目组代码)
.eslintrc.js文件
module.exports = {env: {browser: true,es2021: true,},extends: [require.resolve("@umijs/fabric/dist/eslint")],parserOptions: {ecmaFeatures: {jsx: true,},ecmaVersion: 12,sourceType: "module",},parser: "babel-eslint",globals: {gtag: true,$: true,_g_deflang: true,require: true,envConfig: true,process: true,React: true,ysf: true,initNECaptcha: true,initNECaptchaWithFallback: true,},// plugins: ["react"],rules: {//"react/jsx-uses-react": 2,"no-nested-ternary": 0, // 允许嵌套三元表达式"no-script-url": 0, // 允许javascript:;"prefer-destructuring": 0, // 关闭强制使用解构"no-plusplus": 0, // 允许使用++和--的操作"array-callback-return": 0, // 允许数组map不返回值"consistent-return": 0,"no-param-reassign": 0, // 允许修改函数形参"no-unused-expressions": 0,"no-restricted-syntax": 0,"react/prop-types": 0,"no-prototype-builtins": 0,"react/no-deprecated": 0, // 关闭react弃用检测"react/no-string-refs": 0,"no-useless-escape": 0,"react-hooks/rules-of-hooks":'error',"react-hooks/exhaustive-deps":'warn',},
};
.eslintignore文件
/lambda/
/scripts/*
.history
serviceWorker.ts
/config/*
/public/*
*.js
.prettierrc.js文件
module.exports = {singleQuote: true,jsxSingleQuote: true,semi: true,
};
.prettierignore文件
**/*.svg
package.json
.umi
.umi-production
/dist
.dockerignore
.DS_Store
.eslintignore
*.png
*.toml
docker
.editorconfig
Dockerfile*
.gitignore
.prettierignore
LICENSE
.eslintcache
*.lock
yarn-error.log
.history
.stylelintrc.js文件
const fabric = require('@umijs/fabric');
module.exports = {...fabric.stylelint,
};
替换package.json中命令
"scripts": {"lint": "umi g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier","lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ","lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style","lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src","lint:prettier": "prettier --check \"src/**/*\" --end-of-line auto","lint:style": "stylelint --fix \"src/**/*.less\" --syntax less","prettier": "prettier -c --write \"src/**/*\"","precommit": "lint-staged","precommit:fix": "npm run lint:fix && npm run prettier && npm run lint:prettier && npm run lint:style","dev": "webpack-dev-server --hot --config config/webpack.dev.conf.js","start": "npm run dev","build": "webpack --progress --config config/webpack.prod.conf.js"},
安装cross-env(运行跨平台设置和使用环境变量的脚本)
1、安装:npm install --save-dev cross-env
2、修改启动命令(原命令前加上 cross-env APP_ENV=development 环境变量):"start:dev": "cross-env APP_ENV=development webpack serve --config webpack.development.js","testing": "cross-env APP_ENV=testing webpack --config webpack.testing.js","build": "cross-env APP_ENV=production webpack --config webpack.production.js","preBuild": "cross-env APP_ENV=preProduction webpack --config webpack.production.js",
3、读取环境变量:process.env.APP_ENV
添加提交前检测
#使用husky lint-staged在commit的时候校检你提交的代码是否符合规范
yarn add husky lint-staged -D
package.json新增如下代码
"lint-staged": {"**/*.less": "stylelint--syntaxless","**/*.{js,jsx,ts,tsx}": "npmrunlint-staged:js","**/*.{js,jsx,tsx,ts,less,md,json}": ["prettier--write"]},"husky": {"hooks": {"pre-commit": "npmrunlint-staged"}}
package.json中全部代码如下
{"name": "reactt-home","version": "1.0.0","description": "reactt-home","main": "index.js","scripts": {"lint": "eslint --ext .js --ext .jsx src","start": "cross-env APP_ENV=development webpack serve --config webpack.development.js","testing": "cross-env APP_ENV=testing webpack --config webpack.testing.js","build": "cross-env APP_ENV=production webpack --config webpack.production.js","preBuild": "cross-env APP_ENV=preProduction webpack --config webpack.production.js","lint-staged": "lint-staged","lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ","lint:fix": "eslint --fix --quiet --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style","lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src","lint:prettier": "prettier --check \"**/*\" --end-of-line auto","lint:style": "stylelint --fix \"src/**/*.less\" --syntax less","prettier": "prettier -c --write \"**/*\""},"author": "shenzhihao","license": "ISC","devDependencies": {"@babel/core": "^7.7.4","@babel/plugin-proposal-class-properties": "^7.7.4","@babel/plugin-transform-object-assign": "^7.8.3","@babel/plugin-transform-runtime": "^7.7.4","@babel/polyfill": "^7.7.0","@babel/preset-env": "^7.7.4","@babel/preset-react": "^7.7.4","@babel/runtime": "^7.7.4","@pmmmwh/react-refresh-webpack-plugin": "^0.5.7","babel-eslint": "^10.1.0","babel-loader": "^8.0.6","babel-plugin-import": "^1.13.0","clean-webpack-plugin": "^3.0.0","compression-webpack-plugin": "^6.0.5","copy-webpack-plugin": "^11.0.0","cross-env": "^7.0.3","css-loader": "^3.2.1","css-minimizer-webpack-plugin": "^4.0.0","css-vars-ponyfill": "^2.4.7","eslint": "^7.25.0","eslint-formatter-pretty": "^4.0.0","eslint-plugin-import": "^2.22.1","eslint-plugin-jsx-a11y": "^6.4.1","eslint-plugin-prettier": "^3.4.0","eslint-plugin-react": "^7.23.2","eslint-plugin-react-hooks": "^4.2.0","file-loader": "^5.0.2","files-finder": "0.0.5","html-webpack-plugin": "^5.5.0","html-withimg-loader": "^0.1.16","image-webpack-loader": "^6.0.0","javascript-obfuscator": "^4.0.0","less": "^3.10.3","less-loader": "^7.0.1","lint-staged": "^11.0.0","mini-css-extract-plugin": "^2.6.1","pre-commit": "^1.2.2","prettier": "^2.2.1","react": "^18.3.1","react-dom": "^18.3.1","react-redux": "^7.1.3","react-refresh": "^0.14.0","react-router-dom": "^5.1.2","react-router-redux": "^4.0.8","redux": "^4.0.4","redux-actions": "^2.6.5","redux-logger": "^3.0.6","redux-thunk": "^2.3.0","style-loader": "^1.0.1","stylelint": "^13.13.1","stylelint-config-css-modules": "^2.2.0","stylelint-config-prettier": "^8.0.2","stylelint-config-rational-order": "^0.1.2","stylelint-config-standard": "^22.0.0","stylelint-declaration-block-no-ignored-properties": "^2.3.0","stylelint-no-unsupported-browser-features": "^4.1.4","stylelint-order": "^4.1.0","terser-webpack-plugin": "^5.3.3","url-loader": "^3.0.0","webpack": "^5.73.0","webpack-cli": "^4.2.0","webpack-dev-server": "^3.11.0","webpack-merge": "^4.2.2","webpack-obfuscator": "^3.5.1"},"dependencies": {"axios": "^0.19.0","classnames": "^2.2.6","cross-env": "^7.0.3","history": "^4.10.1","paho-mqtt": "^1.1.0"},"pre-commit": "lint-staged","lint-staged": {"**/*.less": "stylelint --syntax less","**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js","**/*.{js,jsx,tsx,ts,less,md,json}": ["prettier --write"]}
}
三、在JS项目中添加TS
tsconfig.json配置文件
{"compilerOptions": {"incremental": true ,//增量编译"tsBuildInfoFile": ".tsbuildinfo", //增量编译文件的存储位置"diagnostics": true, //打印诊断信息"target": "ES5", //目标语言版本"module": "commonjs",//生成代码的模块标准"outFile": "./app.js", //将多个相互依赖的文件生成一个文件,可以用在AMD模块中"lib": [], //TS需要引用的库,即声明文件"allowJs": true, //允许编辑JS文件(js,jsx)"outDir": "./out", //指定输出的目录"rootDir": "./" ,//指定输入文件目录 (用于输出)"declaration": false, //生成声明文件"declarationDir": "./d", //声明文件的路径"emitDeclarationOnly": false ,//只生成声明文件"sourceMap": false, //生成目标文件的sourecMap"inlineSourceMap": false,//声明目标文件的inline sourceMap"declarationMap": false,//生成声明文件的sourceMap"typeRoots": [], //声明文件目录 默认node_modules/@types"types": [], //声明文件包"removeComments": false, //删除注释"noEmit": false ,//不输出文件"noEmitOnError": false,//发生错误时不输出文件"noEmitHelpers": false, //不生成helper函数,需要额外安装 ts-helpers"importHelpers": false,//通过tslib引入helper函数,文件必须是模块"downlevelIteration": false,//降级遍历器的实习(es3/es5)"strict": false, //严格的类型检查"alwaysStrict": false,//在代码中注入use strict"strictNullChecks": false, //不允许把null,undefined赋值给其他类型变量"strictFunctionTypes": false, //不允许函数参数双向协变"strictPropertyInitialization": false,//类的实例属性必须初始化"strictBindCallApply": false,//严格的bind/call/apply检查"noImplicitThis": false,//不允许this有隐式的any类型"noUnusedLocals": false,//检查只声明,未使用的局部变量"noUnusedParameters": false,//检查未使用的函数参数"noFallthroughCasesInSwitch": false,//防止switch语句贯穿"noImplicitReturns": false,//每个分支都要有返回值"esModuleInterop": false ,//允许export = 导出, 由import from导入"allowUmdGlobalAccess": false,//允许在模块中访问UMD全局变量"moduleResolution": "node", //模块解析策略"baseUrl": "",//解析非相对模块的基地址"paths": {} ,//路径映射,相对于baseUrl"rootDirs": [], //将多个目录放在一个虚拟目录下,用于运行时"listEmittedFiles": false, //打印输入的文件"listFiles": false,//打印编译的文件(包括引用的声明文件)}
}
package.json部分
安装 typescript和ts-loader
yarn add typescript --D
安装react类型配置
yarn add @types/node @types/react @types/react-dom @types/react-router-dom
初始化 tsconfig.json 文件
npx tsc --init
配置 tsconfig.json
{"compilerOptions": {"target": "es2016", /**指定ECMAScript目标版本**/ "module": "commonjs", /**指定生成哪个模块系统代码**/"esModuleInterop": true,"allowJs": true, /**允许编译js文件**/ "jsx": "preserve", /**支持JSX**/ "outDir": "dist", /**编译输出目录**/ "strict": true, /**启用所有严格类型检查选项**/"noImplicitAny": false, /**在表达式和声明上有隐含的any类型时报错**/ "skipLibCheck": true, /**忽略所有的声明文件的类型检查**/ "forceConsistentCasingInFileNames": true /**禁止对同一个文件的不一致的引用**/ },"include": ["src"],"exclude": ["node_modules"]
}
package.json中scripts新增tsc命令用于检测typescript类型
"tsc": "tsc --noEmit"
Webpack部分
安装ts-loader
yarn add ts-loader eslint-import-resolver-typescript --D
reslove:extensions新增.ts和.tsx
resolve: {extensions: ['.js', '.json', '.ts', '.tsx'],
}
配置webpack,新增ts-loader
{test: /\.tsx?$/, // .ts或者tsx后缀的文件,就是typescript文件use: 'babel-loader', exclude: /node-modules/, // 排除node-modules目录
}
安装@babel/preset-typescript
yarn add @babel/preset-typescript -D
.babelrc新增typescript配置
"presets": [..."@babel/typescript"
],
Eslint部分
安装@typescript-eslint/parser和@typescript-eslint/eslint-plugin
yarn add @typescript-eslint/parser @typescript-eslint/eslint-plugin -D
引入eslint三方配置
yarn add eslint-plugin-shopify -D
.eslintrc.js中新增overrides,检测.ts文件
overrides: [{files: ['*.ts', '*.tsx'],parser: '@typescript-eslint/parser',settings: {'import/resolver': {node: {extensions: ['.js', '.jsx', '.ts', '.tsx', '.css'],},typescript: {alwaysTryTypes: true,},},},plugins: ['@typescript-eslint'],extends: ['plugin:shopify/esnext'],parserOptions: {// project: './tsconfig.json',ecmaFeatures: {jsx: true,},ecmaVersion: 12,sourceType: 'module',},rules: {'no-console': 0, // 如果有console,阻止抛出错误'no-use-before-define': 'off',},},],
.eslintignore新增忽略文件tsconfig.json
.prettier新增
// jsxSingleQuote: true,
extends: ['plugin:shopify/typescript','plugin:shopify/react','plugin:shopify/prettier',],
Tips:
eslint不会报告typescript类型错误,ts如需要检测类型需要使用tsc --noEmit命令
四、本地修改依赖包并应用
本地依赖包版本控制
版本号通常由三部分组成:主版本号、次版本号、补丁版本号,格式为 major.minor.patch。常见的符号有:^:更新时允许自动更新次版本号和补丁版本号,但不会更新主版本号(即不允许跨越大版本升级)。
~:更新时只允许更新补丁版本号,不更新次版本号。
> 或<:指定大于或小于某个版本。
=:指定精确的版本号。
使用 patch-package 工具
1. 安装 patch-package:
2. npm install --save-dev patch-package 或 yarn add patch-package -D
3. 修改依赖包源码:
4. 找到需要修改的依赖包文件路径,例如 node_modules/<dependency-name>/<file-to-patch>。
5. 对文件进行所需的修改。
6. 创建补丁文件:
7. npx patch-package
8. 这将创建一个 .patch 文件在项目的根目录下。
9. 提交补丁文件到版本控制系统: 将生成的 .patch 文件提交到你的版本控制系统中。
10. 自动应用补丁
11. 为了确保每次 npm install 都能自动应用这些补丁,你需要在 package.json 的 scripts 字段中添加一条命令:
12. { "scripts": { "postinstall": "patch-package" } }
13. 这样,在每次执行 npm install 后,patch-package 将会自动查找 .patch 文件并应用它们到相应的 node_modules 中。
相关文章:
现代前端工程化实践:高效构建的秘密
一、前端工程化错误监控 这种监控可以帮助开发人员及时发现和解决问题,提高应用程序的稳定性和可靠性。 1. Sentry:Sentry是一款开源的错误监控平台,可以监控前端、后端以及移动端应用程序中的错误和异常。Sentry提供了实时错误报告、错误分…...
react高级面试题
以下是一些React高级面试题: 一、组件相关 React组件的生命周期有哪些(类组件)?在函数组件中如何实现类似功能? 答案: 类组件生命周期: componentDidMount:组件挂载后调用ÿ…...
html 列动态布局
样式说明: /* 列动态布局,列之间以空格填充 */ li {display: flex;/* flex-direction: column; */justify-content: space-between; }...
C++小等于的所有奇数和=最大奇数除2加1的平方。
缘由 三种思路解题:依据算术推导得到一个规律:小等于的所有奇数和等于最大奇数除以2加1的平方。将在后续发布,总计有十种推导出来的实现代码。 int a 0,aa 1,aaa 0;cin >> a; while (aa<a) aaa aa, aa 2;cout << aaa;i…...
政采云业务网关实践:使用 Higress 统一替代 APISIX/Kong/Istio Ingress
作者:政采云基础架构团队技术专家 朱海峰(片风) 业务网关项目背景 由于一些历史的背景,政采云平台在网关建设上遇到一些问题: 容器网关配置较多,配置方式多样,运维压力较大: 配置…...
【嵌入式 Linux 音视频+ AI 实战项目】瑞芯微 Rockchip 系列 RK3588-基于深度学习的人脸门禁+ IPC 智能安防监控系统
前言 本文主要介绍我最近开发的一个个人实战项目,“基于深度学习的人脸门禁 IPC 智能安防监控系统”,全程满帧流畅运行。这个项目我目前全网搜了一圈,还没发现有相关类型的开源项目。这个项目只要稍微改进下,就可以变成市面上目前…...
安卓7以上抓包证书安装
安卓7以上抓包证书安装 fiddler 用户可以直接试试这个文件 前提是要root过了,如果是模拟器就很容易开启 前提:要有openssl工具,在linux一个指令就可以下载了:sudo apt-get install openssl,windons则是在https://www.openssl.org/…...
【C#】任务调度的实现原理与组件应用Quartz.Net
Quartz 是一个流行的开源作业调度库,最初由 Terracotta 开发,现在由 Terracotta 的一部分 Oracle 所有。它主要用于在 Java 应用程序中调度作业的执行。Quartz 使用了一种复杂的底层算法来管理任务调度,其中包括任务触发、执行、持久化以及集…...
C语言:深入了解指针4(超级详细)
看之前必须得掌握有一定指针的知识,不然会看不懂,如果有不懂的可以看我博客 指针1,指针2,指针3 这三个讲了指针全部的基础知识超级详细,这篇只要是讲一些指针练习题也是非常详细 1. sizeof和strlen的对⽐ 1. 基本定义…...
C#+Redis接收数据并定时3秒钟频率异步保存到数据库
要在C#中实现从Redis接收数据,并以每3秒的频率异步保存到数据库,你可以使用System.Threading.Tasks.Task.Delay或System.Timers.Timer来创建一个定时任务。不过,对于更复杂的定时和调度需求,System.Threading.Tasks.Timer或Quartz.NET等库可能更合适。 在这个场景中,由于…...
CEF132 编译指南 Windows 篇 - 拉取 CEF 源码 (五)
1. 引言 获取 CEF 132 源码是开始编译工作的前提和关键步骤。在完成 depot_tools 的安装和配置后,我们需要通过正确的方式下载和同步 CEF 的源代码。由于 CEF 项目依赖于 Chromium 的大量组件,因此源码的获取过程需要特别注意同步策略和版本管理&#x…...
【鸿蒙开发】第二十四章 AI - Core Speech Kit(基础语音服务)
目录 1 简介 1.1 场景介绍 1.2 约束与限制 2 文本转语音 2.1 场景介绍 2.2 约束与限制 2.3 开发步骤 2.4 设置播报策略 2.4.1 设置单词播报方式 2.4.2 设置数字播报策略 2.4.3 插入静音停顿 2.4.4 指定汉字发音 2.5 开发实例 3 语音识别 3.1 场景介绍 3.2 约束…...
DeepSeek与llama本地部署(含WebUI)
DeepSeek从2025年1月起开始火爆,成为全球最炙手可热的大模型,各大媒体争相报道。我们可以和文心一言一样去官网进行DeepSeek的使用,那如果有读者希望将大模型部署在本地应该怎么做呢?本篇文章将会教你如何在本地傻瓜式的部署我们的…...
让万物「听说」:AI 对话式智能硬件方案和发展洞察
本文整理自声网 SDK 新业务探索组技术负责人,IoT 行业专家 吴方方 1 月 18 日在 RTE 开发者社区「Voice Agent 硬件分享会」上的分享。本次主要介绍了 AI 对话式智能硬件的发展历程,新一波 AI 浪潮所带来的创新机遇、技术挑战以及未来的展望。 在语音交…...
Day38-【13003】短文,二叉树,完全二叉树,二叉树的顺序存储,和链式存储
文章目录 第二节 二叉树二叉树的定义及重要性质n个结点,能组合成多少个不同的二叉树满二叉树、完全二叉树完全二叉树的性质二叉树的性质二叉树的结点数完全二叉树的高度 二叉树的存储顺序存储方式链式存储方式二叉链表的程序实现二叉链表空指针域计算 第二节 二叉树…...
MyBatis常见知识点
#{} 和 ${} 的区别是什么? 答: ${}是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于原样文本替换,可以替换任意内容,比如${driver}会被原样替换为com.mysql.jdbc. Driver。 一个…...
4. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--什么是微服务--微服务设计原则与最佳实践
相比传统的单体应用,微服务架构通过将大型系统拆分成多个独立的小服务,不仅提升了系统的灵活性和扩展性,也带来了许多设计和运维上的挑战。如何在设计和实现微服务的过程中遵循一系列原则和最佳实践,从而构建一个稳定、高效、易维…...
【AI】在Ubuntu中使用docker对DeepSeek的部署与使用
这篇文章前言是我基于部署好的deepseek-r1:8b模型跑出来的 关于部署DeepSeek的前言与介绍 在当今快速发展的技术环境中,有效地利用机器学习工具来解决问题变得越来越重要。今天,我将引入一个名为DeepSeek 的工具,它作为一种强大的搜索引擎&a…...
Linux后台运行进程
linux 后台运行进程:& , nohup-腾讯云开发者社区-腾讯云 进程 &,后台运行,结束终端退出时结束进程。 nohup 进程 &,后台运行,结束终端后依然保持运行。...
unity视频在场景中的使用
(一)软件操作在平面上显示视频播放 1.创建渲染器纹理 2.创建平面 3.在平面上添加Video player 4.视频拖拽到Video player 5.渲染模式选择渲染器纹理 6.把纹理拖到目标纹理上 7.把纹理拖到平面上就可以了 然后运行项目 8.结果 (二&#…...
vue3+vite+eslint|prettier+elementplus+国际化+axios封装+pinia
文章目录 vue3 vite 创建项目如果创建项目选了 eslint prettier从零教你使用 eslint prettier第一步,下载eslint第二步,创建eslint配置文件,并下载好其他插件第三步:安装 prettier安装后配置 eslint (2025/2/7 补充) 第四步&am…...
【电商系统架构的深度剖析与技术选型】
以下是对电商系统架构的深度剖析与技术选型: 一、电商系统架构剖析 整体架构 前台系统:是用户直接交互的部分,包括用户界面、商品展示、购物车、订单结算等模块。需注重用户体验,确保页面设计美观、商品信息清晰、购物流程简便。…...
【Android】Android开发应用如何开启任务栏消息通知
Android开发应用如何开启任务栏消息通知 1. 获取通知权限2.编写通知工具类3. 进行任务栏消息通知 1. 获取通知权限 在 AndroidManifest.xml 里加上权限配置,如下。 <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android…...
【Android开发AI实战】基于CNN混合YOLOV实现多车牌颜色区分且针对车牌进行矫正识别(含源码)
文章目录 引言单层卷积神经网络(Single-layer CNN)📌 单层 CNN 的基本结构📌 单层 CNN 计算流程图像 透视变换矫正车牌c实现🪄关键代码实现:🪄crnn结构图 使用jni实现高级Android开发dz…...
探索前端框架的未来:Svelte 的崛起
引言 在前端开发的世界里,框架更新换代的速度仿佛光速。从 jQuery 到 Angular,再到如今大热的 React 和 Vue,开发者们不断追逐更轻量、更快、更易于维护的框架。如今,Svelte 正悄然崛起,并引发了关于前端框架未来的热烈…...
【工具篇】深度揭秘 Midjourney:开启 AI 图像创作新时代
家人们,今天咱必须好好唠唠 Midjourney 这个在 AI 图像生成领域超火的工具!现在 AI 技术发展得那叫一个快,各种工具层出不穷,Midjourney 绝对是其中的明星产品。不管你是专业的设计师、插画师,还是像咱这种对艺术创作有点小兴趣的小白,Midjourney 都能给你带来超多惊喜,…...
多光谱成像技术在华为Mate70系列的应用
华为Mate70系列搭载了光谱技术的产物——红枫原色摄像头,这是一款150万像素的多光谱摄像头。 相较于普通摄像头,它具有以下优势: 色彩还原度高:色彩还原准确度提升约 120%,能捕捉更多光谱信息,使拍摄照片色…...
数字人|通过语音和图片来创建高质量的视频
简介 arXiv上的计算机视觉领域论文: AniPortrait: Audio-Driven Synthesis of Photorealistic Portrait Animation AniPortrait:照片级真实感肖像动画的音频驱动合成 核心内容围绕一种新的人像动画合成框架展开。 研究内容 提出 AniPortrait 框架&a…...
Vue通过触发与监听事件进行数据传递: 子组件调用 $emit 方法来将数据传递给父组件。
文章目录 引言I 组件事件事件参数defineEmits 宏声明需要抛出的事件事件校验例子:子组件告诉父组件放大所有博客文章的文字II 【详细说明】 子组件通过触发一个事件,将数据传递给父组件调用内建的 `$emit `方法传入事件名称来触发一个事件子组件通过`this.$emit`来触发一个事…...
LLMs瞬间获得视觉与听觉感知,无需专门训练:Meta的创新——在图像、音频和视频任务上实现最优性能。
引言: 问题: 当前的多模态任务(如图像、视频、音频描述生成、编辑、生成等)通常需要针对特定任务训练专门的模型,而现有的方法在跨模态泛化方面存在局限性,难以适应新任务。此外,多模态嵌入反演…...
