一. Webpack
1. npm包
webpack:核心包webpack-cli:webpack命令行工具包-
2. 占位符
[name]:模块名称[id]:模块标识符[hash]:模块标识符的hash[chunkhash]:chunk内容的hash[query]:模块的query,文件名?后面的内容
3. entry
4. output
文件输出output.clean:替代clean-webpack-plugin,在打包前清除dist文件夹
5. module
webpack模块,处理项目中不同类型的模块
rule.test:匹配文件类型rule.loader:设置单个解析器rule.use:设置多个解析器,并可以添加options配置rule.exclude:排除的文件夹;如babel-loader排除/node_modules/rule.generator.filename:指定资源的输出路径和文件名module: {rules: [{test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader'},{test: /\.vue$/,loader: 'vue-loader'},{test: /\.(png|jpe?g|gif|svg)$/,type: 'asset/resource',parser: {dataUrlCondition: {maxSize: 8 * 1024}},generator: {filename: 'assets/img/[contenthash:6][ext]'}}]},
rules.type:设置类型用于匹配模块;有如下值处理不同类型的文件asset/resource:发送一个单独的文件并导出URI,之前通过file-loader实现。可以处理png、jpeg,gif等资源 ```javascript module: { rules: [ { test: /.png/, type: ‘asset/resource’ } ] }
// 所有的png文件都被发送到输出目录,其路径被注入到bundle中 import mainImage from ‘./images/main.png’; img.src = mainImage; // ‘/dist/151cfcfa1bd74779aadb.png’
- `asset/inline`:导出一个data uri,之前通过`url-loader实现`,可以处理svg等```javascriptmodule: {rules: [{test: /\.svg/,type: 'asset/inline'}]}// 所有的svg文件都将作为data uri注入到bundle中import metroMap from './images/metro.svg';block.style.background = `url(${metroMap})`; // url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDo...vc3ZnPgo=)
asset:webpack按照默认规则自动在resource、inline之间选择;默认小于8kb选择视为inline模块;否则视为resource模块。这里使用rule.parser.dataUrlCondition配置多大的模块使用base64内置module: {rules: [{test: /\.(png|jpe?g|gif|svg)$/,type: 'asset',parser: {dataUrlCondition: {maxSize: 8 * 1024}}}]},
6. resolve
配置模块的路径如何解析
resolve.alias:路径的别名,优先级高于其他规则;常用@表示srcresolve: {alias: {'@': path.resolve(__dirname, 'src')}},
7.devtool
配置如何生成source map
development环境推荐eval-cheap-module-source-map
production环境可以不添加这个选项不生成source map各种loader
1) vue-loader
webpack插件VueLoaderPlugin:将定义过的其他规则复制到vue中;如/\.js$/复制到vue文件的<script>标签2) css-loader和style-loader
css-loader用于识别并加载css,style-loader用于将css转换为HTML中的style节点;css-loader importLoaders:有@import语法的时候,importLoaders决定@import模块在使用css-loaders前使用多少个其他的loaders处理// importLoaders为2;说明@import模块在使用css-loader之前使用postcss-loader和sass-loader处理module: {rules: [{test: /\.sass$/,use: ['style-loader',{loader: 'css-loader',options: {importLoaders: 2}},'sass-loader','postcss-loader']}]}
3) sass-loader
支持解析sass,scss。
避免在@import使用webpack中的alias(如@代表src),会识别失败
参考:webpack5 的使用(三):加载 css4) postcss-loader
将css解析成AST,通过其他插件做各种修改最终生成新的css
这是使用postcss添加浏览器前缀的方式
首先安装3个npm包
npm install -D postcss postcss-loader autoprefixer
在处理css,scss,sass的规则中添加postcss-loader
module: {rules: [{test: /\.sass$/,use: ['style-loader',{loader: 'css-loader',options: {importLoaders: 2}},'sass-loader','postcss-loader']}]}
添加postcss.config.js和.browserslistrc
// postcss.config.jsmodule.exports = {plugins: [require('autoprefixer'),// 这是将px转化为vw的插件,不需要请忽略{'postcss-px-to-viewport': {viewportWidth: 375}}]};// .browserslistrc> 0.2%last 1 Chrome versionsnot dead
各种plugin
1) html-webpack-plugin
当使用webpack打包的时候,创建一个HTML文件,并把打包后的静态文件自动插入到html文件中;注意需要设置favicon的路径,这样webpack运行的时候才能正确将favicon.ico放在dist目录下。
参考:webpack5 + vue3 从零配置项目2) clean-webpack-plugin
在打包前清除output配置的文件夹,webpack5中可以用
output.clean: true替代3) webpack-bundle-analyzer
4) terser-webpack-plugin
5) mini-css-extract-plugin
提取css到单独的文件夹;建议从bundle提取css;需要同时设定module和plugin
module: {rules: [{test: /\.css$/,use: [// 生产环境用MiniCssExtractPlugin.loader代理style-loaderMiniCssExtractPlugin.loader,{loader: 'css-loader',options: {importLoaders: 1}},'postcss-loader']},{test: /\.s[ca]ss/,use: [MiniCssExtractPlugin.loader,{loader: 'css-loader',options: {importLoaders: 2}},'sass-loader','postcss-loader']}]},plugins: [new MiniCssExtractPlugin({filename: 'css/[name].css'})]
其他工具
1) webpack-merge
合并各个webpack配置 ```javascript const common = require(‘./webpack.common’); const { merge } = require(‘webpack-merge’);
module.exports = merge(common, { mode: ‘development’ });
<a name="Nxke3"></a>### 二. babel<a name="cIimG"></a>#### 1) babel提供语法转换与polyfill功能1. `@babel/core`:核心包1. `babel-loader`:webpack中处理js的loader包1. `@babel/preset-env`:babel预设环境,它会根据`browserlist`进行语法转换1. `@vue/babel-preset-app`:vue的预设环境;1. `@babel/plugin-transfrom-runtime`:编译时转译代码;所以用于开发环境1. `@babel/runtime`:运行时转译代码,只能处理语法syntax;用于生产环境1. `@babel/runtime-corejs3`:运行转译代码,可以处理语法,引入polyfill处理api;用于生产环境<a name="smoGJ"></a>#### 2) 不同的代码转换配置:<a name="eI3Ll"></a>##### 1. 不做任何配置:原样输出<a name="p4Kc5"></a>##### 2. `@Babel/preset-env`1. 只转换syntax(class,typeof,箭头函数等),不转换api(map,include)1. syntax的转换策略由browserslist而定```javascript// babel.config.jsmodule.exports = {presets: [['@babel/preset-env']]}// .browserslistrc>0.25%
3. @Babel/preset-env + core-js@3
- 转换syntax和api
- syntax的转换策略由browserslist而定
- polyfill从core-js@3中引入
- useBuiltIns:是加载polyfill的策略
- usage,无需手动
import '@babel/polyfill'根据browserslist策略 + 使用情况按需加上polyfill - false,不使用polyfill,如果手动
import '@babel/polyfill'会无视策略全部加载polyfill - entry:需要手动
import '@babel/polyfill',根据浏览器策略加载polyfill,导致用不到的polyfill也会被加进去 ```javascript // babel.config.js module.exports = { presets: [ [ ‘@babel/preset-env’, { corejs: 3, useBuiltIns: ‘usage’ } ] ] }
- usage,无需手动
<a name="qcWLe"></a>##### 4. 组合使用`@babel/preset-env`, `core-js@3`, `@babel/plugin-transform-runtime`, `@babel/runtime-corejs3`4. core-js设置转译api,runtime设置false不转译api4. runtime提取了helper代码,减少了代码重复```json{"plugins": [["@babel/plugin-transform-runtime", // 编译时开发环境转译{"corejs": false, // runtime不转译api,由下面的corejs转译"helpers": true, // 提取helpers代码"regenerator": false}]],"presets": [["@babel/preset-env", // babel转换syntax{"corejs": 3, // corejs转译api,polyfill"useBuiltIns": "usage" // 按需引入}]]}
三. eslint + prettier +vue
1. eslint
.eslintrc.js配置选项的说明
root:停止父目录寻找配置文件parserOptions.sourceType:默认scirpt,如果是ES模块设为moduleparserOptions.parser:默认Espree解析器;如果有babel可以使用@babel/eslint-parser解析器env:预定义的全局变量;可用的环境可以有browser,node,commonjs等globals:添加自定义的全局变量名称extends:扩展;值的说明printWidth:允许的最长宽度semi:是否加分号singleQuote:是否使用单引号trailingComma:是否在末尾追加逗号,可以设置为'none'endOfLine:windows和linux换行报错问题;可以设置为'auto'3. eslint+prettier+vue3+vscode配置最佳实践
安装eslint,prettier,eslint-plugin-vue,eslint-config-prettier,@babel/eslint-parser
npm i -D eslint prettier eslint-plugin-vue eslint-config-prettier @babel/eslint-parser
各个插件的作用如下:
| eslint-plugin-vue | 允许检查vue文件的<template>,<script>和js文件的vue代码 |
|---|---|
| eslint-config-prettier | 关闭eslint中与prettier冲突的规则 |
| eslint-plugin-prettier | 以eslint的方式运行prettier,并报错 |
| @babel/eslint-parser | 允许检查所有合法的babel代码 |
- 添加.eslintrc.js文件,设置eslint ```javascript module.exports = { root: true, // 不从父文件夹检查eslint配置文件 parserOptions: { sourceType: ‘module’, // 默认script,如果是ES模块则是module parser: ‘@babel/eslint-parser’ // 允许所有合法的babel代码 }, env: { // 预设了哪些环境的全局变量 browser: true, node: true, es2021: true }, plugins: [‘prettier’], // 添加eslint-plugin-prettier插件 extends: [ ‘eslint:recommended’, // eslint推荐的配置 ‘plugin:vue/vue3-recommended’, // eslint-plugin-vue包内的vue3配置;vue2使用vue/essential ‘prettier’ // prettier配置 ], globals: { // 自定义全局变量 defineProps: true }, rules: { // 自定义规则 ‘prettier/prettier’: ‘error’ // prettier的规则报错 } };
3. 添加.prettierrc.js文件,设置prettier```javascriptmodule.exports = {printWidth: 100, // 一行文字长度的限制semi: true, // 是否添加分号singleQuote: true, // 是否使用单引号trailingComma: 'none', // 是否追加逗号endOfLine: 'auto' // 处理windows和linux的换行不一致}
此时已经可以lint了,在package.json的scripts添加lint,fix,prettier,format等脚本
{"scripts": {"lint": "eslint --ext .js,.vue src","fix": "eslint --ext .js,.vue src --fix","prettier:fix": "prettier --write \"src/**/*.{js,jsx,ts,tsx,json,css,scss,less,md,vue}","format": "npm run prettier:fix && npm run fix"}}
要在vscode中保存时自动lint;在
.vscode文件夹中添加settings.json```json { “editor.formatOnSave”: true, // 保存时format “editor.codeActionsOnSave”: { “source.fixAll.eslint”: true // 使用eslint来format }, “[vue]”: { “editor.defaultFormatter”: “esbenp.prettier-vscode” }, “[javascript]”: { “editor.defaultFormatter”: “esbenp.prettier-vscode” // 对vue和js使用prettier插件 } }
参考:[ESLint and Prettier with Vite and Vue.js 3](https://vueschool.io/articles/vuejs-tutorials/eslint-and-prettier-with-vite-and-vue-js-3/)<br /> [非vue/cli创建的vue2项目引入eslint和prettier最佳实践总结](https://juejin.cn/post/7073492841715990559)<a name="jGHne"></a>### 四. Typescript + Koa搭建1. 安装typescript```shellnpm i -D typescript
- 安装ts-node-dev,支持在开发中启动并更新node ```shell // shell npm i -D ts-node-dev
// package.json ts-node-dev app.ts
3. 开始安装typescript,koa依赖,koa,node的类型支持```shellnpm i koa @types/koa typescript @types/node
初始化TyepScript配置文件tsconfig.json
tsc --init
在tsconfig.json中配置编译输出的目录
"outdir": "./dist"
为项目添加eslint,ts-eslint-parser和ts-eslint-plugin
npm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
在默认生成的.eslintrc.js中修改一下,这里eslitn使用的最基本的lint配置 ```javascript module.exports = { // 使用环境node env: {
node: true,es2021: true
}, // 定义一个自己的ts解析器 parser: ‘@typescript-eslint/parser’, parserOptions: {
ecmaVersion: 'latest',sourceType: 'module',// 告诉eslint typescript配置文件位置project: ['./tsconfig.json']
},
plugins: [
'@typescript-eslint'
],
extends: [
'eslint:recommended','plugin:@typescript-eslint/recommended','plugin:@typescript-eslint/recommended-requiring-type-checking'
],
rules: { } }
参考:[ESLint x TypeScript](https://github.yanhaixiang.com/linter-guide/practice/eslint_typescript.html#%E5%86%8D%E6%97%A0-tslint)7. 安装prettier,并集成到eslint中```shellnpm i -D prettier eslint-config-prettier
// .prettierrc.jsmodule.exports = {printWidth: 100,semi: true,singleQuote: true,trailingComma: 'none',endOfLine: 'auto'}// eslintrc.jsmodule.exports = {root: true,env: {node: true,es2021: true},parser: '@typescript-eslint/parser',parserOptions: {ecmaVersion: 'latest',sourceType: 'module',project: ['./tsconfig.json']},plugins: ['@typescript-eslint',// 这是eslint-plugin-prettier, 让prettier以eslint的方式运行'prettier'],extends: ['eslint:recommended','plugin:@typescript-eslint/recommended','plugin:@typescript-eslint/recommended-requiring-type-checking',// 使用eslint的拓展,'prettier/@typescript-eslint'的拓展已经被集成到这里'prettier'],rules: {// 配合plugin使用'prettier/prettier': 'error'}}
- vscode保存时自动lint,在setting.json中
{"editor.formatOnSave": true,"editor.codeActionsOnSave": {"source.fixAll.eslint": true},"[typescript]": {"editor.defaultFormatter": "esbenp.prettier-vscode","editor.tabSize": 2}}
五. mock数据的n种方法
1. 同源数据的mock
1) 侵入式的mock
不太推荐,把mock数据import进项目中,要判断运行环境。2) 非侵入式的mock
使用webpack的devServer.setupMiddlewares,它为开发环境提供了自定义的中间件能力;接受一个函数,有middlewares和devServer两个参数;middlewares是个数组,请求按先后顺序在middlewares中处理。中间件是express风格的,因为就是基于express的。+ mockjs封装一下就可以mock啦
参考:webpack devServer setupMiddlewares{devServer: {setupMiddlewares: function(middlewares, devServer) {devServer.app.get('hello', (req, res) => {res.send('hi world')})middlewares.push({name: 'first-middleware',path: '/hi', // 请求的路径middleware: (req, res) => {res.send('hello world')}})return middlewares}}}
2. 跨域数据mock
跨域数据的mock没有什么找到什么好的资料。干脆直接使用koa+mockjs直接起一个node服务。 ```javascript const Koa = require(‘koa’); const Router = require(‘koa-router’); const Mock = require(‘mockjs’);
const app = new Koa(); const router = new Router(); app.use(async (ctx, next) => { ctx.set(‘Access-Control-Allow-Origin’, ctx.headers.origin); ctx.set(‘Access-Control-Allow-Methods’, ‘GET, POST, OPTIONS, PUT, DELETE’); ctx.set(‘Access-Control-Allow-Headers’, ‘*’); ctx.set(‘Access-Control-Allow-Credentials’, true); next(); });
router.get(‘/hi’, (ctx) => { const data = Mock.mock({ description: ‘测试的数据’ }); ctx.body = data; });
app.use(router.routes()).use(router.allowedMethods());
const port = 9091;
app.listen(port, () => {
console.log(‘跨域服务器已启动…’);
console.log(端口${port});
});
<a name="lmPlc"></a>### 六. 如何支持打包后动态修改配置有时候打包后的包需要部署在不同的服务器中,需要支持修改配置文件,以便修改请求地址<a name="z0XH2"></a>#### 1. 在index.html模板中添加script在index.html模板中添加script,注意最好插在头部,防止后面的脚本获取不到。将变量暴露挂载到window下```html<script src="./config.js"></script>
// config.jswindow.config = {BASE_URL: 'http://localhost:8080'}// 项目中直接获取变量window.config.BASE_URL
可以把config.js放在项目static目录下,打包时在webpack中使用copy-webpack-plugin将config文件原封不动的复制到dist根目录下。其实public/favicon.ico文件同样可以复制过去。
2. axios请求拦截
使用请求的方式获取数据config.json; 这种方法较为繁琐,不会污染全局变量
- 首先创建一个axios实例,在请求拦截器中判断配置是否读取到。如果没有读取到则先请求获取数据。请求拦截器的第一个回调函数是支持异步的
- 如果数据没有缓存下来则会去请求获取config
- 严重问题,因为是异步的,所以在返回数据前所有的请求都会进入拦截请求一遍;
解决方案:添加一个tag位,保存const tag = axios.get('config.json'),如果tag已经存在就不再请求
/** 请求拦截 */service.interceptors.request.use(async (config) => {/** 请求配置文件,将BASE_URL存放在localStorage中 */if (!localStorage.get('BASE_URL')) {const response = await axios.get('config.json');const global = response.data;config.baseURL = global?.BASE_URL;localStorage.setItem('BASE_URL', config.baseURL)}return config;},(error) => {return Promise.reject(error);});
七. 如何修改IOS15 Safari顶部状态栏颜色
IOS15的Safari浏览器会根据html头部的meta信息修改状态栏颜色,如果没有会自适应使用background。
在vue中路由使用hash模式,更改background的时候并不会让Safari状态栏主动更新。需要手动设置更新
- vue的html模板中添加
<meta name="theme-color" content="#fff" /> - 使用vue不同的页面
const el = document.querySelector('meta[name="theme-color"]')获取meta元素 设置content属性
el.setAttribute('content', 'red')八. git
1. git回退版本
git reset --hard commit_id回退到某个版本,这个版本之后的提交不保留git revert -n commit_id删除某次提交,这个提交之后的提交保留2. tag和branch区别
tag是一个里程碑,静态的。可以为发布的里程碑打tag
branch是动态的,代码需要向前走九. 工程化项目CDN加速
配合webpack抽离出某些包使用cdn加速
在模板index.html中添加CDN链接,这里我们添加一个axios
<body><div id="app"></div><script src="https://cdn.bootcdn.net/ajax/libs/axios/0.26.1/axios.min.js"></script></body>
在webpack中添加externals,代表不需要将这个模块打包到最终的包中。
externals: {axios: 'axios'},
-
十. TSX+ Vue
自从升级到Vue3,Vue和Webpack就成了路人,Vue官方大力推广自家的vite。诶,vite是要学。
坑点1:@vue/eslint-config-prettier不认prettierrc,所以只能在eslintrc中设置module.exports = {root: true,extends: ['plugin:vue/vue3-essential','eslint:recommended','@vue/eslint-config-typescript/recommended','@vue/eslint-config-prettier'],env: {'vue/setup-compiler-macros': true},rules: {'prettier/prettier': ['warn',{printWidth: 100,semi: true,singleQuote: true,trailingComma: 'none',endOfLine: 'auto'}]}};
