项目技术栈
- 构建工具:webpack @5.63.0
- 编程语言: TypeScript @4.4.4
- 前端框架:vue @3.2.23
- CSS预编译:sass
- 请求工具:axios
- 代码规范:eslint+prettier+stylelint
项目搭建
初始化项目
首先新建一个空文件夹,在该文件夹下执行
npm init -y
webpack相关依赖安装
npm i webpack webpack-cli webpack-merge webpack-dev-server -D
vue相关依赖安装
npm i vue@next vue-router@next vuex@next
这里笔者安装完成的版本分别为:
- vue : "3.2.23"
- vue-router : "4.0.12"
- vuex : "4.0.2"
TS相关依赖安装
npm i typescript -D
并创建tsconfig.json
{
"compilerOptions": {
"target": "es5", // 指定编译后的ECMAScript目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'
"module": "esnext", // 用来指定要使用的模块标准: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'
"strict": true, // 启用所有严格类型检查选项。
"jsx": "preserve", // 指定jsx代码用于的开发环境: 'preserve', 'react-native', or 'react'
"importHelpers": true, // 从 tslib 导入辅助工具函数(比如 __extends, __rest等)
"moduleResolution": "node", // 用于选择模块解析策略,有'node'和'classic'两种类型'
"experimentalDecorators": true, // 模块名到基于 baseUrl的路径映射的列表。
"skipLibCheck": true, // 忽略所有的声明文件( *.d.ts)的类型检查。
"esModuleInterop": true, // 支持在 CommonJs 模块下使用 import d from 'cjs', 解决TypeScript 对于 CommonJs/AMD/UMD 模块与 ES6 模块处理方式相同导致的问题
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查。
"sourceMap": true, // 生成相应的 .map文件。
"baseUrl": ".", // 解析非相对模块名的基准目录, 相对模块不会受baseUrl的影响
"paths": {
// 用于设置模块名称到基于baseUrl的路径映射
"@/*": ["src/*"]
},
"lib": ["esnext", "dom", "dom.iterable", "scripthost"] // lib用于指定要包含在编译中的库文件
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx",
"types/**/*.d.ts",
"types/*.d.ts"
], // 指定要编译的路径列表,但是和files的区别在于,这里的路径可以是文件夹,也可以是文件,可以使用相对和绝对路径,而且可以使用通配符,比如"./src"即表示要编译src文件夹下的所有文件以及子文件夹的文件
"exclude": ["node_modules"] // exclude表示要排除的、不编译的文件,它也可以指定一个列表,规则和include一样,可以是文件或文件夹,可以是相对路径或绝对路径,可以使用通配符
}
HTML集成依赖安装
npm i html-webpack-plugin -D
创建入口文件
1、在文件夹下创建public目录,目录下创建 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="shortcut icon" href="/favicon.ico" />
<title>webpack5+ts+vue3</title>
<meta
name="description"
content="webpack5+ts+vue3搭建项目"
/>
<meta
name="keyword"
content="vue3 kai"
/>
</head>
<body>
<div id="app"></div>
</body>
</html>
2、在文件下创建src目录,然后
创建 App.vue 文件
<template>
<router-view />
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "App",
});
</script>
并创建 index.ts 文件
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
创建webpack配置文件
在文件夹下创建build文件夹,并在build文件夹下创建三个文件 webpack.base.conf.js、webpack.dev.js、webpack.prod.js,写入基本的配置文件,后续再慢慢完善
-
webpack.base.conf.js文件
const path = require("path"); function resolve(dir) { return path.join(__dirname, "..", dir); } const HtmlWebpackPlugin = require("html-webpack-plugin"); module.exports = { entry: { app: resolve("src/index.ts"), }, resolve: { extensions: [".js", ".vue", ".json", ".ts", ".tsx", ".mjs"], alias: { "@": resolve("src"), }, }, module: { rules: [ { test: /\.vue$/, use: [ { loader: "vue-loader", }, ], include: /(src)/, }, ], }, plugins: [ // vue-loader插件 new vueLoader.VueLoaderPlugin(), new HtmlWebpackPlugin({ filename: "index.html", template: resolve("public/index.html"), favicon: resolve("public/favicon.ico"), inject: true, }), ], };
-
webpack.dev.js
const { merge } = require("webpack-merge"); const webpack = require("webpack"); const common = require("./webpack.base.conf"); const path = require("path"); function resolve(dir) { return path.join(__dirname, "..", dir); } const devWebpackConfig = merge(common, { mode: "development", devtool: "eval-cheap-module-source-map", module: { rules: [], }, output: { path: resolve("dist"), filename: "js/[name].[hash].js", chunkFilename: "js/[name].[hash].js", publicPath: "/", }, // 日志打印只打印错误和警告 stats: "errors-warnings", devServer: { host: "0.0.0.0", historyApiFallback: { rewrites: [ { from: /.*/g, to: "/index.html", }, ], }, allowedHosts: "all", port: 8080, // 端口号 open: false, // 自动打开 hot: true, // 热更新 client: { progress: true, // 将运行进度输出到控制台。 overlay: { warnings: false, errors: true }, // 全屏显示错误信息 }, compress: true, // 为所有服务启用gzip 压缩 proxy: { "/api": { target: "...", changeOrigin: true, // 是否是跨域请求 pathRewrite: { "^/api": "", }, }, }, }, plugins: [ new webpack.DefinePlugin({ "process.env.NODE_ENV": "'development'", __VUE_OPTIONS_API__: true, __VUE_PROD_DEVTOOLS__: false, }), ], }); module.exports = devWebpackConfig;
-
webpack.prod.js
const { merge } = require("webpack-merge"); const webpack = require("webpack"); const common = require("./webpack.base.conf"); const path = require("path"); function resolve(dir) { return path.join(__dirname, "..", dir); } module.exports = function (env, argv) { const nodeEnv = env.dev ? "development" : env.test ? "test" : "production"; return merge(common, { mode: "production", devtool: "source-map", module: { rules: [], }, plugins: [ new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify(nodeEnv), __VUE_OPTIONS_API__: true, __VUE_PROD_DEVTOOLS__: false, }), ], output: { path: resolve("dist"), filename: "js/[name].[hash].js", chunkFilename: "js/[name].[hash].js", }, }); };
接着修改 package.json 文件中的 scripts 配置
"scripts": {
"dev": "webpack serve --config build/webpack.dev.js",
"build:dev": "webpack --env dev --config build/webpack.prod.js",
"build:test": "webpack --env test --config build/webpack.prod.js",
"build:prod": "webpack --env prod --config build/webpack.prod.js"
},
样式相关配置
npm i css-loader sass-loader sass postcss postcss-loader postcss-preset-env vue-style-loader -D
对应webpack配置
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
'vue-style-loader',
{
loader: 'css-loader',
options: {
sourceMap: false,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
// postcss-preset-env 内部集成了 autoprefixer 添加css第三方前缀
plugins: ['postcss-preset-env'],
},
},
},
{
loader: 'sass-loader',
options: {
additionalData: `
@use "@/styles/variables.scss" as *; // 全局导入sass变量
@use "@/styles/mixin.scss" as *; // 全局导入sass混入
`,
},
},
],
},
],
}
图片字体等文件配置
webpack5 内置了 asset
模块, 可以代替 file-loader
& url-loader
& raw-loader
处理静态资源,比以前简化了很多
rules: [
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024,
},
},
generator: {
filename: 'images/[base]',
},
exclude: [resolve('src/assets/svg')],
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
type: 'asset',
generator: {
filename: 'files/[base]',
},
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
type: 'asset',
generator: {
filename: 'media/[base]',
},
},
],
babel配置
npm i @babel/cli @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/preset-typescript babel-loader -D
npm i @babel/runtime-corejs3 core-js
-
@babel/cli : Babel 自带了一个内置的 CLI 命令行工具,可通过命令行( 例如 npx babel script.js )编译文件,调试用,可装可不装
-
@babel/core :Bable进行转码的核心npm包
-
@babel/plugin-transform-runtime 和 @babel/runtime-corejs3:
js文件在babel转码后会生成很多helper函数(可能有大量重复),polyfill会在全局变量上挂载目标浏览器缺失的功能,这个插件的作用是将 helper 和 polyfill 都改为从一个统一的地方引入,并且引入的对象和全局变量是完全隔离的
@babel/plugin-transform-runtime这个包的作用是转译代码,转译后的代码中可能会引入@babel/runtime-corejs3 里面的模块,所以前者运行在编译时,后者运行在运行时。
-
@babel/preset-env : 预制套件,里面包含了各种可能用到的转译工具。
-
@babel/preset-typescript : 解析 typescript 的 babel 预设
-
babel-loader : // webpack loader,依赖于 @babel/core,babel-loader作为一个中间桥梁,通过调用babel/core中的api来告诉webpack要如何处理js
-
core-js : JavaScript标准库的 polyfill,@babel/preset-env 引用的包
let babelLoaderConf = {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: ['ie>=8', 'chrome>=62'],
node: '8.9.0',
}, // 转换目标
debug: false, // 是否打印prese-env对当前配置用了哪些插件,以及我们所支持的浏览器集合的数据
useBuiltIns: 'usage', // 按需引入
corejs: '3.0', // corejs版本
},
],
[
'@babel/preset-typescript',
{
allExtensions: true, // 支持所有文件扩展名,否则在vue文件中使用ts会报错
},
],
],
plugins: [
[
'@babel/plugin-transform-runtime',
{
corejs: 3,
},
],
],
},
};
// webpack
rules: [
{
test: /\.(ts|js)x?$/,
use: [babelLoaderConf],
exclude: /node_modules/,
},
],
babel7之后已经有了解析 typescript 的能力,也就不再需要 ts-loader
vue文件webpack配置
因为是vue3的项目,所以 vue-loader 要安装最新的版本,这里笔者安装的版本是16.8.3
npm i vue-loader@next @vue/compiler-sfc -D
webpack 配置
const vueLoader = require('vue-loader')
...
module.exports = {
...
module: {
rules: [
{
test: /\.vue$/,
use: [
{
loader: 'vue-loader',
},
],
include: /(src)/,
},
],
},
plugins: [
// vue-loader插件
new vueLoader.VueLoaderPlugin(),
],
}
加入 vue 对应的类型声明,防止类型报错
新建 types 文件夹, 添加 shims-vue.d.ts 文件
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
代码规范
eslint + prettier + stylelint ,外加 .editorconfig 文件
.editorconfig
.editorconfig 文件可以统一编辑时的规范,例如规范缩进空格等等
// .editorconfig 文件
root = true
[*.{js,jsx,ts,tsx,vue,json,html,css,scss}]
indent_style = space # 缩进风格(tab | space)
indent_size = 2 # 缩进大小
end_of_line = crlf # 控制换行类型(lf | cr | crlf)
insert_final_newline = true # 始终在文件末尾插入一个新行
eslint
用于检测代码是否符合编码规范,符合代码语法逻辑,代码格式等等
npm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-prettier eslint-config-prettier eslint-plugin-vue
- eslint: ESLint的核心代码
- @typescript-eslint/parser:ESLint的解析器,用于解析typescript,从而检查和规范Typescript代码
- @typescript-eslint/eslint-plugin:这是一个ESLint插件,包含了各类定义好的检测Typescript代码的规范
- eslint-plugin-prettier、eslint-config-prettier : eslint 和 prettier 规则兼容
- eslint-plugin-vue : vue的相关解析,提供了vue的rules,包含了vue-eslint-parser,所以不用再手动装 vue-eslint-parser
.eslintrc.js 文件
module.exports = {
root: true,
env: {
node: true,
browser: true,
},
parserOptions: {
parser: "@typescript-eslint/parser", // 解析 .vue 文件里面的 script 标签
sourceType: "module",
ecmaVersion: 12,
},
plugins: ["vue", "@typescript-eslint"],
extends: [
"plugin:vue/recommended",
"plugin:prettier/recommended",
"prettier/@typescript-eslint",
"plugin:@typescript-eslint/recommended",
],
rules: {
indent: ["warn", 2], //缩进风格
},
};
prettier
美化代码
npm i prettier -D
.prettierrc.js 文件
module.exports = {
singleQuote: true, // 使用单引号
tabWidth: 2, // Tab 缩进的长度
endOfLine: 'auto', // 文件尾部换行的形式
semi: false, // 不加分号
};
stylelint
npm i stylelint stylelint-config-prettier stylelint-config-recess-order stylelint-config-standard stylelint-order stylelint-scss -D
根目录下添加 stylelint.config.js 文件
module.exports = {
defaultSeverity: 'warn',
extends: [
'stylelint-config-standard',
'stylelint-config-recess-order', // 属性排序规则
],
plugins: ['stylelint-scss', 'stylelint-order'],
rules: {
'no-invalid-double-slash-comments': null, // 允许双斜杠注释
'custom-property-no-missing-var-function': null,
'no-empty-source': null,
'selector-class-pattern': null,
'alpha-value-notation': null, // 允许小数
'color-function-notation': null, // 允许rgb颜色
'media-feature-name-no-vendor-prefix': true, // 不允许媒体特性名称的前缀, 插件自动添加
'selector-pseudo-element-no-unknown': [
true,
{
ignorePseudoElements: ['deep'], // 忽略deep伪元素
},
],
'at-rule-no-unknown': [
true,
{
ignoreAtRules: [
'mixin',
'include',
'if',
'else',
'extend',
'for',
'$',
'forward',
'use',
], // 忽略规则
},
],
},
}
UI框架引入(element-plus)
这个项目采用的 UI 框架是 element-plus,因为目前这个框架是都是 beta 版本,踩了不少坑后,目前使用的是 1.1.0-beta.24 版本,查看框架官方文档,按需引入使用 unplugin-vue-components 插件
npm i element-plus@1.1.0-beta.24 unplugin-vue-components
按需引入
配置 webpack
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
...
module.exports = {
...
plugins: [
...
// element-plus 按需引入
Components({
resolvers: [
ElementPlusResolver({
importStyle: false, // 不引入style文件,便于后面做主题化
}),
],
}),
],
};
同时需要在webpack配置下mjs的loader
修改 fullySpecified 为 false, 让 element-plus 导入模块可以不加扩展名,避免出现 Module not found
的错误且编译失败
module.exports = {
module: {
rules: [
// element-plus
{
test: /\.mjs$/,
include: /node_modules/,
resolve: {
fullySpecified: false,
},
type: 'javascript/auto',
},
],
},
}
添加按需引入 ts 文件
// element-plus.ts
import type { App } from 'vue'
import {
ElButton,
ElSelect,
...
} from 'element-plus'
const components = [
ElButton,
ElSelect,
...
]
const option = {
size: 'medium',
}
export default function introduceElement(app: App): void {
components.forEach((component) => {
app.use(component)
})
app.config.globalProperties.$ELEMENT = option
}
并把该文件导入入口文件
// index.ts
import introduceElement from '@/utils/vue/element-plus'
const app = createApp(App)
// 按需引入element ui组件
introduceElement(app)
主题化
新建 theme.scss 文件
@forward "element-plus/theme-chalk/src/common/var.scss" with (
$colors: (
"primary": (
"base": #016EFD,
),
"success": (
"base": #016EFD,
),
"warning": (
"base": #faad14,
),
"danger": (
"base": #f56c6c,
),
"error": (
"base": #f56c6c,
),
"info": (
"base": #0076ff,
),
),
$font-path : '~element-plus/dist/fonts' ,
$button-padding-horizontal: (
"default": 80px
)
);
新建 elementPlus.scss 文件
@use './theme.scss' as *;
@use 'element-plus/theme-chalk/src/index.scss' as *;
并在入口文件 index.ts 中引入
import './styles/elementPlus.scss'
至此就完成了主题化设置,试了几个 element-plus 的版本,最后才试出这种 主题化 写法能成功也不会有报错
项目优化
打包体积分析
通过分析各个 bundle 文件的占比大小,来进行针对优化。
npm i -D webpack-bundle-analyzer
我们可以通过在 package.json 中增加 scripts 命令
"build:analyzer": "webpack --env analyzer --config build/webpack.prod.js"
webpack 配置文件
function resolve(dir) {
return path.join(__dirname, "..", dir);
};
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
...
module.exports = function (env, argv) {
const analyzerPlugins = env.analyzer
? [
new BundleAnalyzerPlugin({
analyzerMode: "static",
openAnalyzer: false,
// generateStatsFile: true,
reportFilename: resolve("./report/report.html"),
statsFilename: resolve("./report/stats.json"),
}),
]
: [];
return merge(common, {
mode: "production",
...
plugins: [
...
...analyzerPlugins,
],
});
};
最终的打包大小结果会输出到根目录下的 report 文件夹中
增加编译进度条,优化编译提示
npm i -D progress-bar-webpack-plugin friendly-errors-webpack-plugin
- progress-bar-webpack-plugin : 进度条插件
- friendly-errors-webpack-plugin :优化提示插件
const { merge } = require('webpack-merge')
const webpack = require('webpack')
const { resolve } = require('./utils.js')
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')
const common = require('./webpack.base.conf')
const chalk = require('chalk')
const ProgressBarPlugin = require('progress-bar-webpack-plugin')
const devWebpackConfig = merge(common, {
// 日志打印只打印错误和警告
stats: 'errors-warnings',
...
})
devWebpackConfig.plugins.push(
// 进度条
new ProgressBarPlugin({
format: ` :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`,
clear: true,
}),
// 错误提示
new FriendlyErrorsWebpackPlugin({
// 成功的时候输出
compilationSuccessInfo: {
messages: [
`Your application is running here: http://${devWebpackConfig.devServer.host}:${devWebpackConfig.devServer.port}`,
],
},
// 是否每次都清空控制台
clearConsole: true,
})
)
module.exports = devWebpackConfig
cache缓存
配置 webpack 持久化缓存 cache: filesystem,来缓存生成的 webpack 模块和 chunk,改善构建速度。
使用 cache: filesystem 可以缓存构建过程的 webpack 模板,在二次构建时提速。
function resolve(dir) {
return path.join(__dirname, "..", dir);
};
const devWebpackConfig = merge(common, {
...
// 缓存
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename], // 针对构建的额外代码依赖的数组对象。webpack 将使用这些项和所有依赖项的哈希值来使文件系统缓存失效。
},
cacheDirectory: resolve('temp_cache'),
name: 'scf-cache', // 路径temp_cache/scf-cache
compression: 'gzip',
},
})
清理 dist 文件夹
npm i clean-webpack-plugin -D
这个插件可以在打包时清理 dist 下的旧文件(上次构建的结果),以保证 dist 文件夹中构建结果是最新的。
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
plugins: [
// 清空dist
new CleanWebpackPlugin(),
]
}
css分离
npm i mini-css-extract-plugin -D
CSS 默认是放在 JS 文件中,mini-css-extract-plugin 插件可以将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
将CSS文件抽取出来配置, 还可以防止将样式打包在 js 中文件过大和因为文件大网络请求超时的情况。
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = function (env, argv) {
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
},
{
loader: 'postcss-loader',
},
{
loader: 'sass-loader',
},
],
},
],
},
plugins: [
// css抽离
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash].css',
chunkFilename: 'css/[name].[contenthash].css',
}),
],
})
}
css压缩
npm i css-minimizer-webpack-plugin -D
css-minimizer-webpack-plugin 插件可以优化、压缩 CSS文件。
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
plugins: [
new CssMinimizerPlugin(),
],
};
SVG Sprites图
npm i svg-sprite-loader -D
修改webpack配置, 为指定目录下(src/assets/svg)的svg图片配置Sprites图
module.exports = {
module: {
rules: [
{
test: /\.svg$/,
loader: 'svg-sprite-loader',
include: [resolve('src/assets/svg')],
options: {
symbolId: 'icon-[name]',
},
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024,
},
},
generator: {
filename: 'images/[base]',
},
exclude: [resolve('src/assets/svg')],
},
],
},
}
插件 svg 组件
<template>
<svg :class="svgClass" aria-hidden="true">
<use :xlink:href="iconName"></use>
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true,
},
className: {
type: String,
},
},
computed: {
iconName() {
return `#icon-${this.iconClass}`
},
svgClass() {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
},
},
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
创建ts文件,统一导入svg
import type { App } from 'vue'
import SvgIcon from '@/components/common/svg/svg-icon.vue' // svg组件
const requireAll = (requireContext: any) =>
requireContext.keys().map(requireContext)
const req = require.context('@/assets/svg', false, /\.svg$/)
requireAll(req)
export default function svgIconRegistered(app: App): void {
app.component('SvgIcon', SvgIcon)
}
在入口文件 index.ts 中
import { createApp } from 'vue'
import App from './App.vue'
import svgIconRegistered from '@/utils/vue/svg-component'
const app = createApp(App)
// svg Sprites图
svgIconRegistered(app)
使用示例,menu-icon 是 svg 图文件名
<svg-icon icon-class="menu-icon" class="menu-icon" />
git commit 前的检查、优化
集成 husky 和 lint-staged,husky 能够帮你阻挡住不好的代码提交和推送;lint-staged 可以让每次只检查次提交所修改的文件。
npm i lint-staged husky -D
安装完运行
npx husky install
运行之后会发现项目根目录生成了 .husky 文件夹,在该目录下新建 pre-commit 文件
// pre-commit 文件
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
然后在根目录下新建 lint-staged.config.js 文件,
module.exports = {
'src/**/*.{js,vue,png,svg,jpg,jepg,gif}': [
(filenames) =>
filenames.map(
(filename) => `prettier --write --ignore-unknown '${filename}'`
),
],
}
这样在提交前就会对提交文件进行 prettier 美化