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:

  1. -DIs equivalent to--save-dev; Dependencies required when developing the environment
  2. -SIs 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.

  • conclusionVue2.xSeveral drawbacks of the responsive level:
    1. Object attributenewdeleteUnable to detect -> Solution:Vue.$setVue.delete()
    2. Modify the arrayThe indexlengthProperties cannot be detected ->splice

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 messageFormat verification
  • husky: 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