简介: 本篇文章次要解说如何从一个空目录开始,建设起一个基于webpack + react + typescript的标准化前端利用。
作者 | 刘皇逊(恪语)起源 | 阿里开发者公众号前言本篇文章次要解说如何从一个空目录开始,建设起一个基于webpack + react + typescript的标准化前端利用。技术栈: webpack5 + React18 + TS工程化: eslint + prettier + husky + git hooks反对图片、less、sass、fonts、数据资源(JSON、csv、tsv等)、Antd按需加载以及主题反对热更新、资源压缩、代码拆散(动静导入、懒加载等)、缓存、devServer背景在我的项目开发中,咱们能够应用create-react-app或者飞冰等脚手架工具,那么,为什么咱们要本人来搭建一个标准化我的项目?起因当咱们应用优良的脚手架工具开发我的项目时,当然会晋升很多便当,他们的性能更全面、性能更弱小,然而在这些值得学习的楷模背后,咱们须要从零开始,入手去实现每一个细节和性能,看的再多都不如本人入手实现一个demo更有成果。并且入手实际也能够帮忙咱们了解我的项目打包和编译的原理,进而晋升本人的技术熟练度,扩大咱们的知识面。Webpack 实现工程化方方面面的性能,天然不是 all in one code实现的。从 Webpack 的设计理念和实现原理中,咱们能接触到工程化方面的常识:架构扩大、插件化、缓存机制。学习Webpack也代表着学习前端的发展趋势:例如在webpack的竟对Vite上,咱们能够学到bundleless的理念,跳过了传统的打包这个概念,并且其余先进理念都是咱们须要去学习的中央。开发中,咱们发现应用def、aone等生成一个成熟的前端我的项目模版,不难会发现,我的项目中的babel、weback、prettier、loader等配置文件缺失,而且难以批改现成的脚手架配置,可扩大能力较弱。导致在性能优化方面能做的工作无限,使得开发受到限制。我的项目构造目录├── dist // 默认的 build 输入目录
├── .husky // pre-commit hook
├── webpack.config.js // 全局配置文件及webpack配置文件
├── test // 测试目录
└── src // 源码目录
├── assets // 公共的文件(如image、css、font等)├── components // 我的项目组件├── constants // 常量/接口地址等├── routes // 路由├── utils // 工具库├── pages // 页面模块 ├── Home // Home模块,倡议组件对立大写结尾 ├── ...├── App.tsx // react顶层文件├── typing // ts类型文件
├── .editorconfig // IDE格局标准
├── .eslintignore // eslint疏忽
├── .eslintrc // eslint配置文件
├── .gitignore // git疏忽
├── .prettierrc // prettierc配置文件
├── .babelrc // babel配置文件
├── LICENSE.md // LICENSE
├── package.json // package
├── README.md // README
├── tsconfig.json // typescript配置文件依赖 "dependencies": {
"antd": "^4.22.4", // 懂得都懂"react": "^18.2.0", // 懂得都懂"react-dom": "^18.2.0" // 懂得都懂
},
"devDependencies": {
// babel全家桶"@babel/core": "^7.18.10","@babel/plugin-proposal-class-properties": "^7.18.6", // React class反对"@babel/plugin-transform-runtime": "^7.18.10", // 抽离提取 Babel的注入代码,避免反复加载,减小体积"@babel/preset-env": "^7.18.10", // 提供的预设,容许咱们应用最新的JavaScript"@babel/preset-react": "^7.18.6", // react反对 // ts类型查看"@types/node": "^18.6.4","@types/react": "^18.0.15","@types/react-dom": "^18.0.6",// @types 结尾的是对应包的 TypeScript 类型申明"@typescript-eslint/eslint-plugin": "^5.33.0","@typescript-eslint/parser": "^5.33.0", // webpack loader:解析对应文件"csv-loader": "^3.0.5","sass-loader": "^13.0.2","xml-loader": "^1.2.1","ts-loader": "^9.3.1","less-loader": "^11.0.0", // eslint全家桶"eslint": "^8.21.0","eslint-config-ali": "^14.0.1", // ali前端规约"eslint-config-prettier": "^8.5.0", // 敞开所有不必要或可能与[Prettier]抵触的规定"eslint-import-resolver-typescript": "^3.4.0", // 增加 ts 语法反对 eslint-plugin-import"eslint-plugin-import": "^2.26.0", // ES6+ import/export 语法反对"eslint-plugin-prettier": "^4.2.1", // prettier语法反对"eslint-plugin-react": "^7.30.1", // react语法反对"eslint-plugin-react-hooks": "^4.6.0", // hooks语法反对"eslint-webpack-plugin": "^3.2.0", // webpack plugin"fork-ts-checker-webpack-plugin": "^7.2.13", // 防止webpack中检测ts类型"html-webpack-plugin": "^5.5.0", // 简化HTML文件的创立 ,配合webpack蕴含hash的bundle应用"mini-css-extract-plugin": "^2.6.1", // css拆分"optimize-css-assets-webpack-plugin": "^6.0.1", // css压缩"terser-webpack-plugin": "^5.3.3", // 应用 terser 压缩 js (terser 是一个治理和压缩 ES6+ 的工具)"webpack-bundle-analyzer": "^4.5.0", // webpack打包体积可视化剖析"webpack-cli": "^4.10.0", // 提供脚手架命令"webpack": "^5.74.0", // webpack引擎"webpack-dev-server": "^4.9.3", // 开发环境的live server // 工具"husky": "^8.0.1", // 主动配置 Git hooks 钩子"less": "^4.1.3", // css类型"sass": "^1.54.3", // css类型"typescript": "^4.7.4", // ts"lint-staged": "^13.0.3", // 对暂存的git文件运行linter// prettier 格式化"prettier": "^2.7.1","pretty-quick": "^3.1.3", // 在更改的文件上运行 prettier
}实现过程我的项目初始化首先从一个空目录开始,对我的项目初始化:mkdir demo
cd demo
git init
npm initReact和Babel引入对于一个React我的项目,咱们首先要装置React,写一个Hello World!装置咱们次要的我的项目依赖:tnpm i -S react react-dom因为咱们的浏览器不反对最新的ECMAScript语法,所以咱们须要Babel来本义为ES5或者ES6。装置咱们的Babel来进步兼容性:tnpm i -D @babel/core babel-preset-env babel-preset-react @babel/plugin-proposal-class-properties@babel/core: babel转码的外围引擎babel-preset-env: 增加对ES5、ES6的反对babel-preset-react: 增加对JSX的反对@babel/plugin-proposal-class-properties: 对React中class的反对Webpack引入tnpm i -D webpack webpack-cli webpack-dev-server html-webpack-pluginwebpack: weback插件的外围依赖webpack-cli: 为插件提供命令行工具webpack-dev-server: 帮忙启动live serverhtml-webpack-plugin: 帮忙创立HTML模版Babel配置.babelrc中增加根本配置:{
"presets": ["@babel/react", "@babel/env"],
"plugins": ["@babel/plugin-proposal-class-properties"]
}Babel PluginBabel是代码转换器,借助Babel,咱们能够应用最风行的js写法,而plugin就是实现Babel性能的外围。
这里的配置是为了反对react中class的写法。Babel PresetBabel的Plugin个别拆成尽可能小的粒度,开发者能够按需引进,例如ES6到ES5的性能,官网提供了20+插件,这样能够进步性能和扩展性,然而很多时候一一引入就很让人头大,而Babel Preset就是为此而生,能够视为Presets是相干Plugins的汇合。@babel/react: 反对了React所有的转码需要@babel/env: 不夸大滴讲,仅须要它本人外部的配置项,就能够实现古代JS工程简直所有的转码需要Webpack根本配置新建一个webpack.config.js文件。//webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, '/dist'), filename: 'bundle.js'
},
devServer: {
port: 8080
},
module: {
rules: [ { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader', }, { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ]
},
plugins:[
new HtmlWebpackPlugin({ template: path.join(__dirname,'/src/index.html') })
]
}entry: 入口,开始打包的终点output: 打包文件的地址devServer: live server配置test: 应用loader的文件类型loader: 将要应用的loaderPackage.json根本配置"start": "webpack serve --mode development --open --hot",
"build": "webpack --mode production"mode: process.env.NODE_ENV --> development, 为modules和chunks启用有意义的名称open: 通知server在服务启动后关上默认浏览器hot: 开启热更新写一个React Demo目前的我的项目构造如下图所示:
js和html文件如下图所示:
最初,只有start一下,我的项目就会启动在8080端口。TypeScript配置tnpm install -D typescript ts-loader @types/node @types/react @types/react-domtypescript: TypeScript的次要引擎ts-loader: 本义.ts --> .js 并打包@types/node @types/react @types/react-dom: 对node、react、react dom类型的定义同时在根目录退出tsconfig.json来对ts编译进行配置://_tsconfig.json_
{
"compilerOptions": {
"outDir": "./dist/","noImplicitAny": true,"module": "es6","target": "es5","jsx": "react","allowJs": true,"allowSyntheticDefaultImports": true,"moduleResolution": "Node"
}
}最初在webpack中增加对ts的反对。增加ts-loader://_webpack.config.js_
...
{
test: /.tsx?$/,
exclude: /node_modules/,
loader: 'ts-loader'
}
...设置resolve属性,来指定文件如何被解析://_webpack.config.js_
...
resolve:
{
extensions: [ '.tsx', '.ts', '.js' ],
}
...rename入口://_webpack.config.js_
...
entry: "./src/index.tsx",
...最初启动一下server来看一下ts配置是否正确。
上述咱们的配置其实相当于执行了一次:npx create-react-app my-app --template typescript在这种流程下很是麻烦,将 *.ts 提供给 TypeScript,而后将运行的后果提供给 Babel,而且还要借助很多loader。
那么咱们能不能简化一下这样的流程,因为Babel7中提供的babel-loader就能够完满进行编译ts,答案是能够的,这种形式间接简化了过程。
module: {
rules: [ { test: /\.tsx?$/, exclude: /node_modules/, loader: ['babel-loader'] }]
},并且在.babelrc中也只多了一行@babel/preset-typescript,这种配置更简略,而且打包速度更快一点,逻辑更加清晰。那么为什么还要在我的项目中应用ts-loader呢?ts-loader 在外部是调用了 TypeScript 的官网编译器 -- tsc。所以,ts-loader 和 tsc 是共享 tsconfig.json,所以会提供残缺的报错信息,ts-loader也与 vscode 提供的语法校验体现统一而@babel/preset-typescript有的时候会无奈提供残缺的报错信息和类型提醒治理资源webpack 只能了解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 可能去解决其余类型的文件,并将它们转换为无效的模块中。loader中,test属性能够辨认出哪些文件会被转换;use属性能够定义出转换时,应该是用哪个loader。CSS、Less、Sass装置loader:tnpm i -D less less-loader style-loader css-loader sass sass-loaderwebpack配置://_webpack.config.js_
...
rules: [
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader', }, { test: /\.css$/, use: ['style-loader', 'css-loader'], }, { test: /\.tsx?$/, exclude: /node_modules/, loader: 'ts-loader', }, { test: /\.(less|css)$/, exclude: /\.module\.less$/, use: [ { loader: 'css-loader', options: { importLoaders: 2, sourceMap: !!DEV, }, }, { loader: 'less-loader', options: { sourceMap: !!DEV, }, }, ], }, { test: /\.(sass|scss)$/, use: [ { loader: 'css-loader', options: { importLoaders: 2, sourceMap: !!DEV, }, }, { loader: 'sass-loader', options: { sourceMap: !!DEV, }, }, ], },
...图片、JSON资源对于图片和字体,咱们能够应用内置的Assets Modules来轻松地把这些内容加到咱们的零碎中,对于类型,咱们能够抉择:asset/resource 发送一个独自的文件并导出 URL。asset/inline 导出一个资源的 data URI。asset/source 导出资源的源代码。asset 在导出一个 data URI 和发送一个独自的文件之间主动抉择。//_webpack.config.js_
...
module: {
rules: [{
test: /\.png/,type: 'asset/resource'
}]
},
...对于其余类型资源,咱们须要装置csv-loader、xml-loader等://_webpack.config.js_
...
{
test: /.(csv|tsv)$/i,
use: ['csv-loader'],
},
{
test: /.xml$/i,
use: ['xml-loader'],
},
...搭建开发环境目前,咱们的利用曾经能够失常运行tsx文件,并且在本地进行调试和开发,那么咱们来看看如何设置一个开发环境,来使开发变得更加轻松。//_webpack.config.js_
...
const { DEV, DEBUG } = process.env;
process.env.BABEL_ENV = DEV ? 'development' : 'production';
process.env.NODE_ENV = DEV ? 'development' : 'production';
...
mode: DEV ? 'development' : 'production',
devtool: DEV && 'source-map',
...咱们能够从process.env中获取环境变量来辨别开发环境和生产环境。当webpack在本地打包代码时,咱们能够应用inline-source-map,能够将编译后的代码映射回原始源代码,这样在报错的时候,谬误就会被定为到确切的文件和行数。当然,在生产环境中,为了爱护隐衷,最好把这个设置动静关掉。在开发环境中,webpack-dev-server会为你提供一个根本的web server,并且具备实时从新加载性能。欠缺打包配置与缓存咱们心愿每次打包都把上次的打包文件删除,能够应用CleanWebpackPlugin://_webpack.config.js_
...
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin(),
]
}
...并且,在咱们生产环境,咱们心愿改变后的新版本能够抛弃缓存,并且没有改变的版本能够保留缓存;然而在开发环境,咱们不心愿有缓存,而是每次都是拿到最新的资源。所以,须要对webpack config做一次拆分:分成webpack.prod.js 生产环境打包配置webpack.dev.js 开发环境打包配置外面的区别次要在于打包后的文件名称、sourceMap等。生产环境contenthash:只有模块的内容扭转,才会扭转hash值:output: {
filename: 'js/[name].[contenthash:8].js', // contenthash:只有模块的内容扭转,才会扭转hash值
},开发环境output: {
filename: 'js/[name].[hash:8].js',
}性能优化打包剖析工具能够应用webpack-bundle-analyzer来剖析咱们打包资源的大小:const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
plugins: [
DEBUG && new BundleAnalyzerPlugin(),
]同时设置package.json的启动项资源压缩OptimizeCSSAssetsPlugin次要用来优化css文件的输入,包含摈弃反复的款式定义、砍掉款式规定中多余的参数、移除不须要的浏览器前缀等。TerserPlugin次要用来优化js体积,包含重命名变量,甚至是删除整个的拜访不到的代码块。//_webpack.config.js_
...
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
...
optimization: {
minimizer: [
new TerserPlugin({ parallel: false, terserOptions: { output: { comments: false, }, },}),new OptimizeCSSAssetsPlugin({}),
],
minimize: !DEV, splitChunks: { minSize: 500000, cacheGroups: { vendors: false, }, },
},
...代码拆散资源拆散1)多入口webpack内置的个性可能把代码拆散到不同的bundle 中,而后能够按需加载或并行加载这些文件。代码拆散能够用于获取更小的bundle,以及管制资源加载优先级,如果应用正当,会极大影响加载工夫。//_webpack.config.js_
...
entry: {
index: './src/index.js',
another: './src/another-module.js',
},
output: {
filename: '[name].bundle.js'
...2)Tree ShakingWebpack5在生产环境曾经集成了Tree Shaking性能,不必的代码会被shaking掉:// webpack.config.js
module.exports = {
// ...
mode: 'production',
};然而在开发环境中须要手动配置(Not Recommend):// webpack.config.js
module.exports = {
// ...
mode: 'development',
optimization: {
usedExports: true,
}
};处于好奇,webpack是如何完满的避开没有应用的代码的呢?很简略:就是 Webpack 没看到你应用的代码。Webpack 跟踪整个应用程序的import/export 语句,因而,如果它看到导入的货色最终没有被应用,它会认为那是未援用代码(或叫做“死代码”—— dead-code ),并会对其进行 tree-shaking 。死代码并不总是那么明确的。上面是一些例子:// test.js
// 这会被看作“活”代码,不会做 tree-shaking
import { add } from './math'
console.log(add(5, 6))// 导入但没有赋值给 JavaScript 对象,也没有在代码里用到
// 这会被当做“死”代码,会被 tree-shaking
import { add, minus } from './math'
console.log('hello webpack')// 导入整个库,然而没有赋值给 JavaScript 对象,也没有在代码里用到
// 十分奇怪,这居然被当做“活”代码,因为 Webpack 对库的导入和本地代码导入的解决形式不同。
import { add, minus } from './math' // 死的
import 'lodash' // 活的
console.log('hello webpack')
所以对于这种三方库咱们能够应用上面的Shimming办法。留神 Webpack 不能百分百平安地进行 tree-shaking。有些模块导入,只有被引入,就会对应用程序产生重要影响。一个很好的例子就是全局样式表,或者设置全局配置的JavaScript 文件。Webpack 认为这样的文件有“副作用”。具备副作用的文件不应该做 tree-shaking,因为这将毁坏整个利用。比拟好的通知Webpack你的代码有副作用的办法就是在package.json外面设置sideEffects。{
"name": "your-project",
"sideEffects": ["./src/some-side-effectful-file.js", "*.css"]
}3)Shimming预置依赖对于下面的lodash库无奈被shaking,咱们能够应用细粒度shimming预置的办法来优化,首先引入ProvidePlugin插件,把应用程序中的模块依赖,改为一个全局变量依赖,让咱们先移除 lodash 的 import语句,改为通过插件提供它,并且提取出join办法来全局应用它:// _src/index.tsx
console.log(join(['hello', 'webpack'], ' '))
// webpack.config.js
plugins: [
new webpack.ProvidePlugin({
//_: 'lodash'// 如果没正文的话,须要这样援用console.log(_.join(['hello', 'webpack'], ' '))join: ['lodash', 'join'],
})
]细粒度Shimming一些遗留的模块依赖的this指向的window对象,咱们能够应用import-loaders,它对依赖 window 对象下的全局变量(比方 $ 或 this )的第三方模块十分有用。CommonJS 上下文中,这将会变成一个问题,也就是说此时的 this指向的是 module.exports。在这种状况下,你能够通过应用 imports-loader笼罩 this 指向:// webpack.config.js
module: {
rules: [
{ test: require.resolve('./src/index.js'), use: 'imports-loader?wrapper=window',},
]
},4)公共局部提取避免反复能够应用splitChunk,提取出代码中的公共局部://_webpack.config.js_
...
minimize: !DEV,
splitChunks: {
minSize: 500000, cacheGroups: { vendors: false, },
},
...minSize:造成一个新代码块最小的体积cacheGroups:这里开始设置缓存的 chunks5)按需拆散在React我的项目中,代码按需拆散能够应用如下办法,webpack 把 import() 作为一个分离点(split-point),并把引入的模块作为一个独自的 chunk。import() 将模块名字作为参数并返回一个 Promoise 对象,即 import(name) -> Promise。//_index.tsx_
...
const WdAndDxEntry = lazy(() => import(/ webpackChunkName: "wd-and-dx" / '../../old-code/component/wd-and-dx/entry'));
const WdAndDxFallback = () => ()
const SSRCompatibleSuspense = (props: Parameters< typeof Suspense>['0']) => {
const isMounted = useMounted();
if (isMounted) {
return < Suspense {...props} />;
}
return < >{props.fallback}< />;
}
...
return (
< SSRCompatibleSuspense fallback={< WdAndDxFallback />}>
< WdAndDxEntry className="" data={data} style={{ height: 150, }} />
< /SSRCompatibleSuspense>
); 6)拆散三方库配置 dependOn option 选项,这样能够在多个 chunk 之间共享模块://_webpack.config.js_
...
module.exports = {
entry: {
index: { import: './src/index.js', dependOn: 'shared',
},
another: {
import: './src/another-module.js',dependOn: 'shared',
},
shared: 'lodash',
}
}
...CSS拆散该插件MiniCssExtractPlugin将CSS提取到独自的文件中。它为每个蕴含CSS的JS文件创建一个CSS文件。//_webpack.config.js_
...
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
...
{
test: /.(sass|scss)$/,
use: [
{ loader: MiniCssExtractPlugin.loader,},{ loader: 'css-loader', options: { importLoaders: 2, sourceMap: !!DEV, },},{ loader: 'sass-loader', options: { sourceMap: !!DEV, },},
],
},
...
DEBUG && new BundleAnalyzerPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].css',
}),
...进步构建速度当我的项目体积增大时,编译工夫也随之减少。其中工夫大头就是ts的类型检测耗时。ts-loader 提供了一个 transpileOnly 选项,它默认为 false,咱们能够把它设置为 true,这样我的项目编译时就不会进行类型查看,也不会输入申明文件。//_webpack.config.js_
...
module: {
rules: [
{ test: /\.tsx?$/, use: [ { loader: 'ts-loader', options: { transpileOnly: true } } ]}
]
}
...能够看一下开关这个选项后的前后比照:开启查看前$ webpack --mode=production --config ./build/webpack.config.js
Hash: 36308e3786425ccd2e9d
Version: webpack 4.41.0
Time: 2482ms
Built at: 12/20/2019 4:52:43 PM
Asset Size Chunks Chunk Namesapp.js 932 bytes 0 [emitted] main
index.html 338 bytes [emitted]
Entrypoint main = app.js
[0] ./src/index.ts 14 bytes {0} [built]
Child html-webpack-plugin for "index.html":
1 assetEntrypoint undefined = index.html[0] ./node_modules/html-webpack-plugin/lib/loader.js!./index.html 489 bytes {0} [built][2] (webpack)/buildin/global.js 472 bytes {0} [built][3] (webpack)/buildin/module.js 497 bytes {0} [built] + 1 hidden module
✨ Done in 4.88s.敞开查看后$ webpack --mode=production --config ./build/webpack.config.js
Hash: e5a133a9510259e1f027
Version: webpack 4.41.0
Time: 726ms
Built at: 12/20/2019 4:54:20 PM
Asset Size Chunks Chunk Names
app.js 932 bytes 0 [emitted] main
index.html 338 bytes [emitted]
Entrypoint main = app.js
[0] ./src/index.ts 14 bytes {0} [built]
Child html-webpack-plugin for "index.html":
1 asset
Entrypoint undefined = index.html
[0] ./node_modules/html-webpack-plugin/lib/loader.js!./index.html 489 bytes {0} [built]
[2] (webpack)/buildin/global.js 472 bytes {0} [built]
[3] (webpack)/buildin/module.js 497 bytes {0} [built]
1 hidden module
✨ Done in 2.40s.From 4.88s --> 2.4s,然而短少了类型查看。这里官网举荐了一个解决方案,应用fork-ts-checker-webpack-plugin,它在一个独自的过程上运行类型查看器,此插件应用 TypeScript 而不是 webpack 的模块解析,有了 TypeScript 的模块解析,咱们不用期待webpack 编译。能够极大放慢编译速度。//_webpack.config.js_
...
module: {
rules: [{ test: /\.tsx?$/, use: [ { loader: 'ts-loader', options: { transpileOnly: true } } ]}
]
},
plugins: [
new ForkTsCheckerWebpackPlugin()
]
...用editorconfig对立编辑器标准在根目录新建.editorconfig即可,留神不要与已有的lint规定抵触:// .editorconfighttp://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[makefile]
indent_style = tab
indent_size = 4Antd配置babel中配置按需加载:{
"presets": ["@babel/react", "@babel/env"],
"plugins": [
"@babel/plugin-proposal-class-properties",[ "import", { "libraryName": "antd", "libraryDirectory": "es", "style": true // or 'css' }, "antd"]
]
}webpack中定制主题:module: {
rules: [ // 解决 .css { test: /\.css$/, use: ['style-loader', 'css-loader'], }, // 解决 .less { test: /\.less$/, use: [ 'style-loader', 'css-loader', // less-loader { loader: 'less-loader', options: { lessOptions: { // 替换antd的变量,去掉 @ 符号即可 // https://ant.design/docs/react/customize-theme-cn modifyVars: { 'primary-color': '#1DA57A', }, javascriptEnabled: true, // 反对js }, }, }, ], },]
}
留神款式必须加载 less 格局,一个常见的问题就是引入了多份款式,less 的款式被 css 的款式笼罩了。ESlint配置ESlint次要性能蕴含代码格局和代码品质的校验,并且能够配置pre-commit来标准代码的提交。tnpm install -D eslint eslint-webpack-plugin @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-reacteslint: eslint次要引擎eslint-webpack-plugin: webpack loader@typescript-eslint/parser: 帮忙ESlint lint ts代码@typescript-eslint/eslint-plugin: 蕴含TS扩大规定的插件eslint-plugin-react: 蕴含React扩大规定的插件ESlint配置文件// eslintrc
module.exports = {
parser: '@typescript-eslint/parser', // ESlint Parser
extends: [
'plugin:react/recommended', // 从@eslint-plugin-react中抉择举荐的规定'plugin:@typescript-eslint/recommended', // 从@typescript-eslint/eslint-plugin抉择举荐的规定
],
parserOptions: {
ecmaVersion: 2018, // 帮忙转化最先进的ECMAScript性能sourceType: 'module', // 容许imports的用法ecmaFeatures: { jsx: true, // JSX兼容},
},
rules: {
},
settings: {
react: { version: 'detect', // 通知eslint-plugin-react自动检测最新版本的react},
},
};Prettier配置尽管 ESLint 也能够校验代码格局,但 Prettier 更善于,所以我的项目中个别会搭配一起应用。为了防止二者的抵触,个别的解决思路是禁掉 ESLint 中与 Prettier 抵触的规定,而后应用 Prettier 做格式化, ESLint 做代码校验。prettier配置文件{
"arrowParens": "avoid",
"bracketSpacing": true,
"embeddedLanguageFormatting": "auto",
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"jsxBracketSameLine": true,
"jsxSingleQuote": false,
"printWidth": 100,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"requirePragma": false,
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5",
"useTabs": true,
"vueIndentScriptAndStyle": false
}代码提交标准prettier 只是保障了在通过编辑器(vs code)进行格式化代码的时候,格式化成须要的格局(当然能够通过配置 onSave 在代码保留时主动格式化),然而无奈保障所有人都会被动进行。因而进行主动格式化显得十分重要,而主动格式化的是机会抉择 pre-commit 最失当,通过 git hook ,可能在 commit 之前格式化好代码(如果曾经 commit,会将暂存转为提交,生成提交记录,须要回滚才会撤销)。tnpm i -D pretty-quick prettier husky pretty-quick: 配合git-hooks进行代码检测,并且fixhusky: 能够通过配置的形式来应用git-hooks,防止手动批改package.json设置"pretty": "./node_modules/.bin/pretty-quick --staged"
...
"husky": {
"hooks": { "pre-commit": "tnpm run pretty"}
},Webpack残缺配置最初贴一下残缺的配置,因为Aone公布自动更新版本号,所以不必拆分config文件来依据环境设置缓存,并且配置曾经尽可能简化,拆分反而会减少保护老本。//_webpack.config.js_
//webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const ESLintPlugin = require('eslint-webpack-plugin');
const { DEV, DEBUG } = process.env;
process.env.BABEL_ENV = DEV ? 'development' : 'production';
process.env.NODE_ENV = DEV ? 'development' : 'production';
module.exports = {
entry: './src/index.tsx',
output: {
path: path.join(__dirname, '/dist'),filename: 'bundle.js',clean: true,
},
devServer: {
port: 8080,
},
mode: DEV ? 'development' : 'production',
devtool: DEV && 'source-map',
module: {
rules: [ { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader', }, { test: /\.tsx?$/, exclude: /node_modules/, loader: 'ts-loader', }, { test: /\.css$/, use: ['style-loader', 'css-loader'], }, // 解决 .less { test: /\.less$/, use: [ 'style-loader', 'css-loader', // less-loader { loader: 'less-loader', options: { lessOptions: { // 替换antd的变量,去掉 @ 符号即可 // https://ant.design/docs/react/customize-theme-cn modifyVars: { 'primary-color': '#1DA57A', 'border-color-base': '#d9d9d9', // 边框色 'text-color': '#d9d9d9' }, javascriptEnabled: true, // 反对js }, }, }, ], }, { test: /\.(sass|scss)$/, use: [ { loader: MiniCssExtractPlugin.loader, }, { loader: 'css-loader', options: { importLoaders: 2, sourceMap: !!DEV, }, }, { loader: 'sass-loader', options: { sourceMap: !!DEV, }, }, ], }, { test: /\.png/, type: 'asset/resource', }, { test: /\.(woff|woff2|eot|ttf|otf)$/i, type: 'asset/resource', }, { test: /\.(csv|tsv)$/i, use: ['csv-loader'], }, { test: /\.xml$/i, use: ['xml-loader'], },],
},
optimization: {
minimizer: [ new TerserPlugin({ parallel: false, terserOptions: { output: { comments: false, }, }, }), new OptimizeCSSAssetsPlugin({}),],minimize: !DEV,splitChunks: { minSize: 500000, cacheGroups: { vendors: false, },},
},
resolve: {
modules: ['node_modules'],extensions: ['.json', '.js', '.jsx', '.ts', '.tsx', '.less', 'scss'],
},
plugins: [
new HtmlWebpackPlugin({ template: path.join(__dirname, '/src/index.html'), filename: 'app.html', inject: 'body',}),DEBUG && new BundleAnalyzerPlugin(),new MiniCssExtractPlugin({ filename: '[name].css', chunkFilename: '[name].css',}),new ESLintPlugin(),new ForkTsCheckerWebpackPlugin(),
].filter(Boolean),
};总结这篇文章次要记录了开发过程中从我的项目初始化开始,再到一个标准化前端我的项目的搭建途程。波及相干代码标准、开发环境搭建、生产环境优化等,旨在打造出一个可疾速应用的古代Webpack5.x+React18.x+Typescript+Antd4.x模板,以供在当前的理论业务场景需要中零老本应用。举荐浏览1.研发效力的思考总结2.对于技术能力的思考和总结3. 如何结构化和清晰地进行表白 重磅来袭!2022上半年阿里云社区最热电子书榜单! 千万浏览量、百万下载量、上百本电子书,近200位阿里专家参加编写。多元化抉择、全畛域笼罩,汇聚阿里巴巴技术实际精髓,读、学、练一键三连。开发者藏经阁,开发者的工作伴侣~点击这里,查看详情。原文链接:https://click.aliyun.com/m/10...本文为阿里云原创内容,未经容许不得转载。