preface
Why the wheel? Doesn’t the official scaffolding smell good? Making wheels is just to deepen our understanding of technology, and to understand the principle of its back knowledge on the basis of knowing how to use it, so as to flexibly use its knowledge in various business needs and achieve twice the result with half the effort
The following is the real project development environment set up by the company. I extracted some important knowledge points as internal technology sharing.
Next, we use Webpack5 to build a complete Vue3 development environment!!
Initialize a directory
Step 1: Initialize package.json
npm init -y
Copy the code
Step 2: Install webPack
npm install webpack webpack-cli -D
Copy the code
Note:
-D
Is equivalent to--save-dev
; Dependencies required when developing the environment-S
Is equivalent to--save
; Required in the production environment
Step 3: Initialize directories and files
-
Create the webpack.config.js file to write the Webpack configuration
// webpack.config.js const path = require('path'); module.exports = { mode: 'development'.entry: './src/index.js'.output: { filename: '[name].js'.path: path.resolve(__dirname, 'dist')}}Copy the code
-
Create a SRC directory to hold the source code
// src/index.js console.log('test webpack') Copy the code
-
Modify the scripts field in webpack.config.js
{ // ... "scripts": { "build": "webpack" }, / /... } Copy the code
-
packaging
Enter NPM run build in the project root terminal.
After successful packaging, a dist folder will be automatically created in the root directory of the project, and the main.js file in the folder will be our packaged file.
Configuring Core Functions
Transfer ES6 + ES5
Some browsers cannot parse advanced syntax such as ES6+, so you need to convert it to low-level syntax that the browser can parse (for example, Internet Explorer).
Step 1: Install dependencies
npm install @babel/core babel-loader @babel/preset-env -D
Copy the code
Step 2: Modify the webpack.config.js configuration
const path = require('path');
module.exports = {
// ...
module: {
rules: [{test: /\.js$/,
use: {
loader: 'babel-loader'.options: {
presets: ['@babel/preset-env'}}}]}}Copy the code
Note: If you do not want to write the configuration to the configuration file, you can create a babel.config.js or babelrc.js file in the project root directory.
Processing style
Since WebPack by default can only package JS files that deal with the commonJs specification, processing other files requires the corresponding processor to process them.
Step 1: Install dependencies
npm install style-loader css-loader less less-loader -D
Copy the code
Step 2: Modify the webpack.config.js configuration
const path = require('path');
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /\.css$/,
use: [
'style-loader'.'css-loader'] {},test: /\.less$/,
use: [
'style-loader'.'css-loader'.'less-loader'}]}}Copy the code
Note: Loader configuration has many optimizations, which will be explained in detail later.
Processing static resources such as images
In the same way, webpack files other than JS files need to be handled by a specific processor.
Step 1: Install dependencies
npm install url-loader file-loader -D
Copy the code
Step 2: Modify the webpack.config.js configuration
const path = require('path');
module.exports = {
// ...
module: {
rules: [
// ...
{
test: /\.(jpg|png|jpeg|gif|bmp)$/,
use: {
loader: 'url-loader'.options: {
limit: 1024.fallback: {
loader: 'file-loader'.options: {
name: '[name].[ext]'}}}}}, {test: /\.(mp4|ogg|mp3|wav)$/,
use: {
loader: 'url-loader'.options: {
limit: 1024.fallback: {
loader: 'file-loader'.options: {
name: '[name].[ext]'}}}}}]}}Copy the code
Creating an HTML file
How do we automatically insert packaged JS files into HTML templates?
Step 1: Install dependencies
npm install html-webpack-plugin -D
Copy the code
Step 2: Modify the webpack.config.js configuration
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'.filename: 'index.html'.title: 'Vue3 + TS -> Web App'}})]Copy the code
Note: the configuration of dynamic page title, should be in the template < title > tag in the content into a % > < % = htmlWebpackPlugin. The options. The title
Development server
Every time after packaging, I need to manually click the generated index.html to see the effect. Can I let Webpack automatically open the packaged file in the browser?
Step 1: Install dependencies
npm install webpack-dev-server -D
Copy the code
Step 2: Modify the webpack.config.js configuration
module.exports = {
// ...
devServer: {
port: 3000.hot: true.open: true.contentBase: '.. /dist'
},
// ...
}
Copy the code
Clear packaged files
If the packaged file is hash, the generated file will remain in the dist directory each time it is packaged. We can use this plug-in to help us clean up the previous packaged file before each packaging.
Step 1: Install dependencies
npm install clean-webpack-plugin -D
Copy the code
Step 2: Modify the webpack.config.js configuration
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
// ...
plugins: [
// ...
new CleanWebpackPlugin()
]
}
Copy the code
Setting environment Variables
There are several common ways to set environment variables:
- imperative
- Configuration type
- Create the.env file
- cross-env
We set environment variables as cross-env because it can be set across terminals
Step 1: Install dependencies
npm install cross-env -D
Copy the code
Step 2: Modify the package.json configuration
{
// ...
"scripts": {
"webpack": "cross-env NODE_ENV=development webpack"
}
// ...
}
Copy the code
Packaging by environment
In our usual project development, there are generally: development environment, test environment and production environment. What package files are appropriate for the development environment? Suitable for test and production environments? With these questions in mind let’s configure a multi-environment package.
Packing compression
The ultimate requirement for us to develop a project is to achieve the minimum packaging volume in a fully functional situation, because this can provide a great deal of user experience.
-
Compress HTML files
Modify the webpack.config.js configuration
const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { // ... plugins: [ new HtmlWebpackPlugin({ // ... + minify: { + collapseWhitespace: true.// Remove whitespace + removeComments: true // Remove the comment+}}).// ...]}Copy the code
-
Compressing CSS Files
Step 1: Install dependencies
npm install mini-css-extract-plugin optimize-css-assets-webpack-plugin -D Copy the code
Step 2: Modify the webpack.config.js file
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); module.exports = { // ... module: { rules: [ // ... { test: /\.css$/, use: [ + MiniCssExtractPlugin.loader, 'css-loader'] {},test: /\.less$/, use: [ + MiniCssExtractPlugin.loader, 'css-loader'.'less-loader']},// ...]},plugins: [ // ... new OptimizeCssAssetsWebpackPlugin(), new MiniCssExtractPlugin({ filename: 'css/[name].css'}})]Copy the code
Note: Purgecss-webpack-plugin is used to remove useless CSS
-
Compressed JS files
Step 1: Install dependencies
npm install terser-webpack-plugin -D Copy the code
Step 2: Modify the webpack.config.js file
const TerserWebpackPlugin = require('terser-webpack-plugin'); module.exports = { // ... optimization: { minimize: true.minimizer: [ new TerserWebpackPlugin() ] }, // ... } Copy the code
Note: Uglifyjs-webpack-plugin does not support compressed ES6 syntax code
-
The compressed image
Step 1: Install dependencies
npm install image-webpack-loader -D Copy the code
Step 2: Modify the webpack.config.js file
module.exports = { // ... module: { rules: [ // ... { test: /\.(jpg|png|jpeg|gif|bmp)$/, use: [ { loader: 'url-loader'.options: { limit: 1024.fallback: { loader: 'file-loader'.options: { name: '[name].[ext]'}}}}, {loader: 'image-webpack-loader'.options: { mozjpeg: { progressive: true,},optipng: { enabled: false,},pngquant: { quality: [0.65.0.90].speed: 4 }, gifsicle: { interlaced: false,},webp: { quality: 75}}}]},// ...]},// ... } Copy the code
Note: CNPM installation is used when installing the image-webpack-loader dependency. NPM installation error:
Module build failed (from ./node_modules/image-webpack-loader/index.js): Error: Cannot find module 'gifsicle' Copy the code
Integrated TypeScript
TypeScript is an essential skill for front-end engineers, and Vue3’s source code is completely rewritten in TS. Therefore, it must be mastered and flexibly applied to real projects. There are some core concepts to master: generics, enumerations, interfaces, classes, functions, and so on
Configure the environment
Step 1: Install dependencies
npm install typescript ts-loader -D
Copy the code
Step 2: Modify the webpack.config.js file
module.exports = {
// ...
module: {
rules: [{test: /\.ts$/,
use: [
'ts-loader']},// ...]},// ...
}
Copy the code
Step 3: Initialize the tsconfig.json file
tsc --init
Copy the code
The key content
- The generic
- interface
- function
- .
Identify.vue files
Step 1: Install dependencies
npm install vue@next -S
npm install vue-loader@next @vue/compiler-sfc
Copy the code
Note: Vue2. X installs vue-template-complier
Step 2: Modify the webpack.config.js file
const { VueLoaderPlugin } = require('vue-loader/dist/index');
module.exports = {
// ...
module: {
rules: [{test: /\.vue$/,
use: [
'vue-loader']]}},plugins: [
new VueLoaderPlugin()
]
}
Copy the code
Step 3: Introduce Vue into the index.js file
// index.js
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app')
Copy the code
Added app. vue file
// App.vue
<template>
<div>
<div>Parse the Vue file</div>
<p>{{name}}</p>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const name = ref('txm')
return {
name
}
}
})
</script>
Copy the code
Note: defineComponent is just for good syntax hints when using Vue3
Composition API
Vue3, inspired by React Hooks, rewrites the former Options API into a functional API, which decouples the code to a large extent, is also tree-shaking, and improves the reuse rate of the code. Although mixins in Vue2 can complete the separation of common logic code, mixins also have the following disadvantages: naming conflicts, methods with the same name and calculation attributes can be overridden, life cycles with the same name are executed and executed first in mixins, etc.
Some of the more common Composition apis are:
- Reactive, REF, effect, Watch, computed, life cycle, H function, toRefs and so on
For more details, see the Vue composite API
Responsive system
We all know that the reactive underlying core of Vue2. X uses Object.defineProperty to hijack the getter and setter for each property of the Object, do dependency collection when the property is acquired, and trigger updates when the property is updated.
DefineReactive and method in Vue2. X
// src\core\observer\index.js
if (Array.isArray(value)) {
this.observeArray(value)
} else {
this.walk(value)
}
// Process objects
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
// Handle arrays
observeArray (items: Array<any>) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function, shallow? : boolean) {
const dep = new Dep()
letchildOb = ! shallow && observe(val)Object.defineProperty(obj, key, {
enumerable: true.configurable: true.get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend() // Collect dependencies
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
if (setter) {
setter.call(obj, newVal)
} else{ val = newVal } childOb = ! shallow && observe(newVal) dep.notify()// Notification update}})}Copy the code
From the core principle above, we can see that when dealing with arrays and objects, the judgment is handled separately. When the data is multi-layered, starting with recursive operations and hijacking every property of the object is not good for performance.
- conclusion
Vue2.x
Several drawbacks of the responsive level:- Object attribute
new
和delete
Unable to detect -> Solution:Vue.$set
和Vue.delete()
- Modify the array
The index
和length
Properties cannot be detected ->splice
- Object attribute
Vue3 uses Proxy as the underlying responsive core API, and the source code is as follows:
// packages\reactivity\src\reactive.ts
function createReactiveObject(
target: Target,
isReadonly: boolean,
baseHandlers: ProxyHandler<any>,
collectionHandlers: ProxyHandler<any>
) {
const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
return proxy
}
Copy the code
The createReactiveObject method is the core method to create a reactive type. You can see that the Proxy directly listens to the entire object without treating the array and object separately.
Note: when learning Vue3 source code, it is necessary to master the grammar of ES6 new features such as Set, WeakSet, Map, WeakMap and Reflect in advance.
The new features
Vue3 also comes with several new built-in components for developers: Fragments, Suspense, Teleport
Integrated Vue – the Router
The basic use
Step 1: Install dependencies
npm install vue-router@4 -S
Copy the code
Step 2: Create home.vue and me.vue files
// Home.vue
<template>
<div>Home page</div>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'Home'
})
</script>
// Me.vue
<template>
<div>My page</div>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
name: 'Me'
})
</script>
Copy the code
Step 3: Create the router.js file
import { createRouter, createWebHistory } from 'vue-router';
import Home from './Home.vue';
import Me from './Me.vue';
const routerHistory = createWebHistory();
const router = createRouter({
history: routerHistory,
routes: [{path: '/home'.name: 'Home'.component: Home
},
{
path: '/me'.name: 'Me'.component: Me
}
]
})
export default router;
Copy the code
Step 4: Modify the index.js file
// index.js
import { createApp } from 'vue';
import App from './App.vue';
+ import router from './router.js';
createApp(App).use(router).mount('#app')
Copy the code
We can see that the route usage is still a little different from the original Vue2. X, all using function mode
Integrated Vuex
The basic use
Step 1: Install dependencies
npm install vuex@next -S
Copy the code
Step 2: Create the store.js file
import { createStore } from 'vuex';
const store = createStore({
state: {
name: 'vuex'
},
getters: {},
actions: {},
mutations: {},
modules: {}})export default store;
Copy the code
Step 3: Modify the index.js file
import { createApp } from 'vue';
import App from './App.vue';
import router from './router.js';
+ import store from './store.js';
createApp(App).use(router).use(store).mount('#app')
Copy the code
Step 4: Get the data from VUEX in app.vue
<template>
<div>
<! -... -->
<p>Get vuex data {{count}}</p>
<! -... -->
</div>
</template>
<script>
import { defineComponent, computed } from 'vue';
import { useStore } from 'vuex';
export default defineComponent({
setup() {
const store = useStore();
const count = computed(() = > store.state.count)
return {
count
}
}
})
</script>
Copy the code
Note: Using computed packages to get data from the Store ensures that the data is responsive
If you are not familiar with the basic usage of Vue3, you can read this basic introduction to quickly master the development of Vue3 bucket
Integrated Vant
Step 1: Install dependencies
npm install vant@next -S
Copy the code
According to the need to introduce
Step 1: Install dependencies
npm i babel-plugin-import ts-import-plugin -D
Copy the code
Step 2: Modify the configuration
JS version
// babel.config.js
module.exports = {
plugins: [['import',
{
libraryName: 'vant'.libraryDirectory: 'es'.style: true,},'vant',]]};Copy the code
TS version
const tsImportPluginFactory = require('ts-import-plugin');
module.exports = {
// ...
module: {
rules: [{test: /\.ts$/,
use: [
{
loader: 'ts-loader'.options: {
transpileOnly: true.getCustomTransformers: () = > ({
before: [
tsImportPluginFactory({
libraryName: 'vant'.libraryDirectory: 'es'.style: (name) = > `${name}/style/less`,})]}),compilerOptions: {
module: 'es2015',},}},],exclude: /node_modules/
},
// ...]}};Copy the code
Rem layout adaptation
Step 1: Install dependencies
npm install lib-flexible -S
npm install postcss-pxtorem -D
Copy the code
Step 2: Add the.postcsrc. Js file
module.exports = {
plugins: {// autoprefixer: {
Browsers: ['Android >= 4.0', 'iOS >= 8']
// },
'postcss-pxtorem': {
// rootValue: 37.5, // Vant's official root font size is 37.5
rootValue({file}) {
return file.indexOf('vant')! = = -1 ? 37.5 : 75
},
propList: [The '*'].selectorBlackList: ['.norem'] // filter out. Norem - classes that start with norem conversion}}},Copy the code
Note: Browsers need to configure the package.json option, or else packaging gets warnings
// package.json
{
// ...
"browserslist": [
"1%" >."last 2 versions"."not dead"."Android > = 4.0"."iOS >= 8"]}Copy the code
Step 3: Introduction and use
// index.js
import { createApp } from 'vue';
+ import 'lib-flexible/flexible';
import App from './App.vue';
import router from './router.js';
import store from './store.js';
createApp(App).use(router).use(store).mount('#app')
Copy the code
// Home.vue
<template>
<div>Home page<v-button plain hairline type="primary">Thin border button</v-button>
<v-button plain hairline type="primary">Thin border button</v-button>
</div>
</template>
<script>
import { defineComponent, ref } from "vue";
import { Button } from "vant";
export default defineComponent({
name: "Home".components: {
"v-button": Button
}
});
</script>
Copy the code
To optimize the
Optimization is generally the key part of the project. Good optimization methods can greatly reduce the packaging volume of the project while ensuring the integrity of the function. The following are several commonly used optimization methods in the actual development of the project:
Canonical directory structure
After using Webpack5 to configure each environment, normalize the directory structure of the project. The normalized directory structure of the project is as follows:
tree -I "node_modules"
Copy the code
├ ─ dist │ ├ ─ CSS │ └ ─ js | | - the favicon. Ico | | - index. HTML ├ ─ node_modules ├ ─ public | | - index. HTML | | - the favicon. Ico └ ─ SRC | ├ ─ API | ├ ─ components | ├ ─ hooks | ├ ─ the router | ├ ─ store | ├ ─ utils | └ ─ views | | - App. Vue | | - main. Ts | - gitigore |-babel.config.js |-package.json |-shims-vue.d.ts |-tsconfig.json |-webpack.config.jsCopy the code
See if this directory structure looks a bit like the directory of projects generated by Vue scaffolding
Note: Since TypeScript only understands.ts files, not.vue files, create a.d.ts file in the project root directory.
// shims-vue.d.ts
declare module '*.vue' {
import { ComponentOptions } from 'vue';
const componentOptions: ComponentOptions;
export default componentOptions;
}
Copy the code
Packing Friendly Tips
Step 1: Install dependencies
npm install friendly-errors-webpack-plugin node-notifier -D
Copy the code
Step 2: Modify the webpack.config.js file
const path = require('path');
+ const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
+ const notifier = require('node-notifier');
+ const icon = path.join(__dirname, 'public/icon.jpg');
module.exports = {
// ...
plugins: [
new FriendlyErrorsWebpackPlugin({
onErrors: (severity, errors) = > {
notifier.notify({
title: 'Webpack compilation failed ~'.message: `${severity} ${errors[0].name}`.subtitle: errors[0].file || ' ', icon, }); }}),// ...]};Copy the code
Analyze the package file size
Step 1: Install dependencies
npm install webpack-bundle-analyzer -D
Copy the code
Step 2: Modify the webpack.config.js file
+ const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
// ...
plugins: [
new BundleAnalyzerPlugin(),
// ...]};Copy the code
Step 3: Modify the package.json file
{
"scripts": {
// ...
"analyzer": "webpack --progress"}},Copy the code
The console executes the NPM Run Analyzer system to automatically start the HTTP server that packages the report; If you don’t want to start it every time, you can generate a stats.json file and view it later when you want to.
+ const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
// ...
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'disabled'.generateStatsFile: true
}),
// ...]};Copy the code
Add a command to the scripts field in package.json:
{
"scripts": {
// ...
+ "analyzers": "webpack-bundle-analyzer --port 3000 ./dist/stats.json"}},Copy the code
By packaging the report, you can intuitively know which dependency packages are large, so you can make specific changes.
Packing speed
This plug-in makes it very clear and intuitive to display the time taken to package each dependency on the console
Step 1: Install dependencies
npm install speed-measure-webpack5-plugin -D
Copy the code
Note: An error is reported when speed-measure-webpack-plugin is configured in Webpack5
Step 2: Modify webpack.config.js
const SpeedMeasureWebpack5Plugin = require('speed-measure-webpack5-plugin');
const smw = new SpeedMeasureWebpack5Plugin();
module.exports = smw({
// options
})
Copy the code
Narrow your packing
Exclude: excludes certain files, similar to blacklist include: includes the files, similar to the whitelist
If both are configured, exclude has a higher priority than include
const path = require('path');
module.exports = {
// ...
module: {
rules: [{test: /\.js$/,
use: {
loader: 'babel-loader'.options: {
presets: ['@babel/preset-env'],}},exclude: /node_modules/,
include: path.resolve(__dirname, 'src')},// ...],}};Copy the code
The cache
By default, cache can be configured in babel-loader. If other loaders want to cache, you need to download cache-loader
Step 1: Download the dependencies
npm install cache-loader -D
Copy the code
Step 2: Modify the webpack.config.js file
const path = require('path');
module.exports = {
// ...
module: {
rules: [{test: /\.js$/,
use: {
loader: 'babel-loader'.options: {
presets: ['@babel/preset-env'],
+ cacheDirectory: true}},// ...
},
{
test: /\.css$/,
use: ['cache-loader'.'style-loader'.'css-loader'],}// ...],}};Copy the code
other
- resolve
- external
- optimization
- , etc.
Uniform code Specification
The unified code specification includes code validation, code formatting, git pre-commit validation, editor configuration, and so on
Eslint
ESLint is an open source JavaScript code checking tool
-
New.eslintrc.js file
module.exports = { root: true.// This is used to tell ESLint that the current configuration file cannot be looked up by its parent env: { node: true.// This specifies the global variables of the environment. The following configuration specifies the Node environment }, extends: ['plugin:vue/recommended'.'@vue/prettier'].rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off'.'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'.'vue/no-v-html': 'off',},parserOptions: { parser: 'babel-eslint'.parser: 'babel-eslint'.ecmaVersion: 7.sourceType: 'module'.ecmaFeatures: { // Add ES feature support to enable ES6 syntax recognition jsx: true,}},overrides: [],};Copy the code
-
New.eslintignore file
#.eslintignore files that do not need to be checked src/assets src/icons public dist node_modules Copy the code
Perttier
Prettier is a code formatting tool. To be able to format our code according to our rules
-
The file prettier.config.js was added
module.exports = { printWidth: 80.tabWidth: 2.useTabs: false.semi: false.singleQuote: true.quoteProps: 'as-needed'.jsxSingleQuote: false.trailingComma: 'es5'.bracketSpacing: true.jsxBracketSameLine: false.arrowParens: 'always'.htmlWhitespaceSensitivity: 'ignore'.vueIndentScriptAndStyle: true.endOfLine: 'lf',}Copy the code
stylelint
Stylelint helps us normalize CSS writing, unify style and reduce errors
-
New.stylelintrc.js file
module.exports = { extends: ['stylelint-config-recess-order', 'stylelint-config-prettier'], } Copy the code
EditorConfig
-
New.editorConfig file
root = true [*] charset = utf-8 end_of_line = lf indent_size = 2 indent_style = space insert_final_newline = true trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false Copy the code
Configure Git Message
Step 1: Install dependencies
npm install -g commitizen cz-conventional-changelog
echo '{ "path": "cz-conventional-changelog" }' > ~/.czrc
Copy the code
Once installed, you can use git Cz instead of git commit
yarn add husky @commitlint/config-conventional @commitlint/cli -D
Copy the code
commitlint
: Responsible for used againstcommit message
Format verificationhusky
: Responsible for providing easy accessgit hook
Step 2: Create commitlint.config.js in the root directory
echo 'module.exports = {extends: ["@commitlint/config-conventional"]}; ' > ./commitlint.config.js
Copy the code
Note: Use UTF-8, otherwise Husky will report an error
Step 3: Introduce Husky in package.json file
"husky": {
"hooks": {
"commit-msg": "commitlint -e $GIT_PARAMS"}}Copy the code
Step 4: Use
- git add .
- Git Cz select and enter
- Git push -u origin branchName
Automated publishing
let client = require('scp2');
const ora = require('ora');
const chalk = require('chalk');
const spinner = ora(chalk.green('Publishing to the server... '))
spinner.start()
client.scp('./dist', { // Local package path
'host': 'xxx.xxx.x.xxx'.// Server IP address
'post': '22'.// Server IP address
'username': 'xxxx'./ / user name
'password': '* * * * *'./ / password
'path': '/opt/stu_app_website' // Where the project needs to be deployed to the server
}, err= > {
spinner.stop();
if(! err) {console.log(chalk.green('Project release completed'))}else {
console.log('err', err)
}
})
Copy the code
The company’s real project was to integrate CI/CD automated test releases
conclusion
It takes a lot of time to complete the configuration of a project from zero to a handful, but when you really implement it manually, you will find that it is good for your growth