Build front-end engineering

In our daily development projects, we basically use official scaffolding for development. Then there are the downsides to using official scaffolding: you can’t customize some features very well. I hope it will be helpful to summarize how I built front-end engineering from scratch.

1. The purpose of engineering

  • Front-end engineering is to improve team cooperation efficiency through process standardization and standardization
  • Improve code quality through componentization and modularization
  • Use build tools and automation tools to improve development efficiency

2. Engineering development process

  • Compile => Pack (Merge) => Compress (Webpack or rollup)
  • Code check => ESLint
  • Test = > jest
  • Contract awarding
  • Continue to inherit

3. Selection of compilation tools

There are two main types of compilation tools, webPack and Rollup, which we’ll show you how to configure.

3.1 webpack configuration

const webpack = require("webpack");
// plugin for HTML, you can specify an index. HTML to insert the corresponding JS file into the page
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
module.exports = {
  mode: "development".devtool:false.entry: "./src/index.tsx".output: {
    filename: "[name].[hash].js".path: path.join(__dirname, "dist"),},// Webpack5 has built-in webpack-dev-server, if you need to install webpack-dev-server separately
  devServer: {
    hot: true.contentBase: path.join(__dirname, "dist"),
    historyApiFallback: {
      index: "./index.html",}},resolve: {
    extensions: [".ts".".tsx".".js".".json"].alias: {
      "@": path.resolve("src"), // This will enable @ to point to the SRC directory}},module: {
    rules: [{test: /\.tsx? $/,
        loader: "ts-loader"}],},plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html"
    }),
    // WebPack's built-in plugin. Hot update usage
    new webpack.HotModuleReplacementPlugin()
  ],
};
Copy the code

Note: Webpack5 has webpack-dev-server built in and can be started directly using the Webpack server command.

3.2 Rollup configuration

import ts from 'rollup-plugin-typescript2'; // Parse the ts plugin
import {
  nodeResolve
} from '@rollup/plugin-node-resolve'; // Resolve the plugin for the third-party module
import commonjs from '@rollup/plugin-commonjs'; // Make third-party non-ESM modules support compilation
import json from 'rollup-plugin-json'; // Support json compilation
import serve from 'rollup-plugin-serve'; // Start the local service plug-in
import path from 'path'

// Differentiate the development environment
const isDev = process.env.NODE_ENV === 'development'
// Rollup supports ES6 syntax
export default {
  input: 'packages/index.ts'.output: {
    // amd iife commonjs umd..
    name:'hp'.format: 'umd'./ / esm module
    file: path.resolve(__dirname, 'dist/index.js'), // Export documents
    sourcemap: true.// Generate mapping files from the source code
  },
  plugins: [
    commonjs({
      include: 'node_modules/**'.// Default: undefined
       extensions: ['.js'.'.ts']
      // exclude: ['node_modules/foo/**', 'node_modules/bar/**'], // Default: undefined
      
    }),
    json({
      // All JSON files will be parsed by default,
      // but you can also specifically include/exclude files
      include: 'node_modules/**'.// preferConst: true, 
      // namedExports: true // Default: true
    }),
    nodeResolve({ // Third-party file parsing
      browser:true.extensions: ['.js'.'.ts']
    }),
    ts({
      tsconfig: path.resolve(__dirname, 'tsconfig.json')
    }),
    isDev ? serve({
      openPage: '/public/index.html'.contentBase: ' '.port: 3000
    }) : null]}Copy the code

3.3 Compiling typescript files.

There are two schemes, one based on Babel and one based on TSC.

Based on TSC compilation

/ / webpack
// cnpm i typescript ts-loader -D
module: {
    rules: [{test: /\.tsx? $/,
        loader: "ts-loader"}],},/ / the rollup
 // cnpm i rollup-plugin-typescript2 -D
  
ts({
      tsconfig: path.resolve(__dirname, 'tsconfig.json')})Copy the code

Compile based on Babel

Introduce the Babel plugin in WebPack and Rollup respectively

Babel configuration file

const presets = [
    ['@babel/preset-env', { // A default set
        // chrome, opera, edge, firefox, safari, ie, ios, android, node, electron
        Targets and BrowerSlist are merged to take the lowest version
        // Enable a more canonical conversion, but slower, which defaults to 'false', and for now, a more rigorous conversion, including some code checks.
        spec: false.// There are two modes: normal and loose. Normal is closer to ES6 and Loose is closer to ES5
        loose: false.// "amd" | "umd" | "systemjs" | "commonjs" | "cjs" | false, defaults to "commonjs"
        modules: false.// Indicates the ESM module

        // Print the plugin usage
        debug: false.useBuiltIns: 'usage'.// Import on demand
        corejs: { version: 3.proposals: true } // Consider using 2, or 3
    }],
    ['@babel/preset-typescript', { // Ts configuration
        'isTSX': true.'allExtensions': true}].'@vue/babel-preset-jsx'
];
const plugins = [
    '@babel/plugin-syntax-jsx'.'@babel/plugin-transform-runtime'.'@babel/plugin-syntax-dynamic-import'.// ['@babel/plugin-transform-modules-commonjs'], support tree Sharking must be an ESM module, so remove this plugin
  	// Support decorator pattern development
  	['@babel/plugin-proposal-decorators', { 'legacy': true }],
  	['@babel/plugin-proposal-class-properties', { 'loose': true}]];module.exports = {
    presets,
    plugins
};

Copy the code

Recommendation: Babel compilation is recommended for webPack development in business. Edit js library compiled using TSC.

3.4 Sorting out TS Configuration Files

The basic parameters

parameter explain
target Used to specify the version target after compilation
module Generated in module form: None, CommonJS, AMD, System, UMD, ES6, ES2015, or ESNext Only AMD and System can be used with outFile. Es6 and ES2015 are available if target is ES5 or lower
lib Compile-time introduction of ES function libraries, including: ES5, ES6, ES7, DOM, etc. If target is es6: [“dom”, “es6”, “dom.iterable”, “scripthost”]
allowJs Whether to allow the compilation of JS files, default is false, that is, not compiling JS files
checkJs Whether to check and report errors in JS files. Default is false
jsx Specifies the development environment for which the JSX code will be usedpreserveKeep JSX syntax, extension name.jsxReact-native means that the JSX syntax is preserved, and the js extension means that the react syntax is compiled into ES5 syntaxBreak down
declaration Whether to generate the corresponding.d.tsDeclaration file
declarationDir The path for storing the generated. D. ts file is the same as that for the. Ts file by default
declarationMap Whether to generate a map file for the declaration file. D. ts
sourceMap Whether to generate at compile time.mapfile
outFile Whether to merge the output files into one file, the value is a file pathname, only setmoduleThe value ofamdandsystemModule is supported
outDir Specify the output folder
rootDir The root directory of the compiled file, where the compiler looks for entry files
composite Whether to compile the build reference project
removeComments Whether to delete comments from the compiled file
noEmit No compilation files are generated
importHelpers Whether the introduction oftslibIn the auxiliary tool function
downlevelIteration When the target isES5orES3When, for thefor-of,spreadanddestructuringProvides full support for iterators in
isolatedModules Specifies whether to treat each file as a separate module. Defaults to true

Strictly check **

parameter explain
strict Whether all type checks are enabled
noImplicitAny The default any type is not allowed
strictNullChecks When set to true, null and undefined values cannot be assigned to values that are not of either type
strictFunctionTypes Whether bidirectional covariant checking for function parameters is used
strictBindCallApply Whether the parameters of bind, call, and apply bound methods are rigorously checked
strictPropertyInitialization Check whether the non-undefined property of the class has been initialized in the constructor
noImplicitThis Don’t allowthisThe value of the expression isanyType of time
alwaysStrict Specifies that each module is always checked in strict mode

Additional checks **

parameter explain
noUnusedLocals Check to see if any variables are defined but not used
noUnusedParameters Checks for arguments that are not used in the body of the function
noImplicitReturns Check whether the function returns a value
noFallthroughCasesInSwitch Check whether there are cases in the switch that do not use break

Module parsing check **

parameter explain
moduleResolution To select a module resolution policy, yesnodeandclassicTwo types,Detailed instructions
baseUrl Resolves the base directory for non-relative module names
paths Set module name to based onbaseUrlPath mapping for
rootDirs You can specify a list of paths that the compiler will put into a folder at build time
typeRoots Specifies a list of paths to declaration files or folders
types Use to specify which modules to include
allowSyntheticDefaultImports Allow default imports from modules that do not have default exports
esModuleInterop Create a namespace for the imported content to enable mutual access between CommonJS and ES modules
preserveSymlinks The symbolic link is not resolved to its real path

Sourcemap check * *

parameter explain
sourceRoot The debugger should find the TypeScript file, not the source file location
mapRoot The debugger finds the location of the map file, not the build file, specifying the root path of the map file
inlineSourceMap Specifies whether to compile the contents of the map file in the same JS file as the JS file
inlineSources Whether to further include the contents of the.ts file in the output file

** Test options **

parameter explain
experimentalDecorators Whether to enable the experimental decorator feature
emitDecoratorMetadata Whether to provide metadata support for decorators

Test options

parameter explain
files Configure an arraylist containing relative or absolute paths to specified files. The compiler will only compile the files that are included in the files list
include Include also specifies a list of paths to compile, but unlike files, the path can be either a folder or a file
exclude Exclude indicates the files to exclude and not compile. It can also specify a list
extends Extends extends extends configuration from this configuration file by specifying a path to another tsconfig.json file
compileOnSave When we edit the saved files in the project, the editor will followtsconfig.jsonThe configuration file is regenerated
references An array of objects specifying the items to reference

Tsconfig. json basic configuration

{
  "compilerOptions": {
    "outDir": "./dist"."sourceMap": true."strict": true."noImplicitAny": true."strictNullChecks": true."module": "commonjs"."target": "es5"."jsx": "react"."baseUrl": "."."paths": {
      "@ / *": [
        "src/*"]}},"include": [
    "./src/**/*"]}Copy the code

The TS configuration file is sorted out.

4. Code verification

4.1 Purpose of code review:

  • Canonical code promotes teamwork
  • Canonical code can reduce maintenance costs
  • Canonical code facilitates code review

4.2 Common code specification documents

  • Someone whose Chinese version
  • Standard Chinese
  • Baidu front-end coding specifications
  • styleguide
  • CSS Coding Specification

4.3 Code and Checking plug-ins esLint (vscode)

Search for eslint in the vscode store and install it

The configuration takes effect in method 1 :(modifying vscode)

{
  "eslint.options": { "configFile": "C:/mydirectory/.eslintrc.json"}}Copy the code

Method 2: Add a configuration file to each individual project

4.4 Installing modules

cnpm i eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
Copy the code

4.5 Basic Configuration

  • English rules
  • Chinese rules
  • You need to addparserOptionsTo support modular writing
module.exports = {
    "parser":"@typescript-eslint/parser"."plugins": ["@typescript-eslint"]."rules": {"no-var":"error"."no-extra-semi":"error"."@typescript-eslint/indent": ["error".2]},"parserOptions": {
        "ecmaVersion": 6."sourceType": "module"."ecmaFeatures": {
          "modules": true}}}// package.json
"scripts": {+"lint": "eslint --fix --ext .js,.vue src",}Copy the code

4.6 Code and Check

cnpm i husky lint-staged –save-dev

// package.json 

"husky": {
    "hooks": {
      "pre-commit": "lint-staged"}},"lint-staged": {
    "src/**/*.js": [
      "eslint --fix"."git add"]."src/**/*.less": [
      "stylelint --fix"."git add"]},Copy the code

5. Unit testing

5.1 Installation and Configuration

cnpm i jest @types/jest ts-jest jest -D / / rely on the package
npx ts-jest config:init // Generate the configuration file

// package.json
 "scripts": {+"jest-test": "jest -o",
 +  "jest-coverage": "jest --coverage"
  },
Copy the code

5.2 Configuration File Display

module.exports = {
  roots: [
    "<rootDir>/packages"].testRegex: 'test/(.+)\\.test\\.(jsx? |tsx?) $'.transform: {
    "^.+\\.tsx? $": "ts-jest"
  },
  moduleFileExtensions: ['ts'.'tsx'.'js'.'jsx'.'json'.'node']};Copy the code

Note: This is just a brief list of what is needed, and a sufficient configuration. To configure the configuration based on specific requirements, check the documentation.

6. Git Submission specification and Changelog (package sending)

6.1 the advantages

  1. Good Git Commit benefits
  • Can speed up the code review process
  • You can generate a Changelog from the metadata of git Commit
  • Let other developers know the reason for the change

6.2 Good commit

  • Commitizen is a tool for formatting commit messages

  • Validate-commit – MSG checks whether the project’s commit message conforms to the format

  • Conventional -changelog-cli Can generate change logs from Git metadata

  • Unify git Commit standards for teams

  • You can use the Angular Git Commit log as the basic specification

    • The types of submissions are limited to feat, fix, docs, style, refactor, perf, Test, chore, Revert, and so on
    • The submitted information is divided into two parts: the title (do not capitalize the first letter and do not punctuate the end) and the body content (describe the changes).
  • Log submission friendly type selection prompts to use the Commitize tool

  • Guarantee mechanism for refusing to submit logs that do not meet the required format

    • You need to usevalidate-commit-msgtool
  • Unified Generation of Changelog documents

    • useconventional-changelog-clitool
cnpm i commitizen  validate-commit-msg conventional-changelog-cli -D
commitizen init cz-conventional-changelog --save --save-exact
git cz
Copy the code

Use git cz command: this is easy to do.

6.3 Format of submission

<type>(<scope>):<subject/>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
Copy the code
  • Represents the type of the commit, such as fixing a bug or adding a feature
  • Represents scope, such as a page or a component
  • Topic, which Outlines the content of this submission
  • Detailed impact content
  • Fixed bugs and issue links
type meaning
feat The new feature
fix Fix the bug
docs Only the document is modified, such as README, CHANGELOG, CONTRIBUTE, and so on
style Only whitespace, indentation, preferences, and other information are modified, without changing the code logic
refactor Code refactoring, no new features or bug fixes
perf Optimizations related to improved performance and experience
test Test cases, including unit tests and integration tests
chore Change the build process, or add dependent libraries and tools
revert Roll back to the previous version
ci Update CI configuration and script files

6.4 Upgrading package.json

Installation depends on CNPM install standard-version inquirer shelljs -d

Execute script:

const inquirer = require('inquirer'); // Command line interaction module
const shell = require('shelljs');

if(! shell.which('git')) {
    shell.echo('Sorry, this script requires git');
    shell.exit(1);
}

const getVersion = async() = > {return new Promise((resolve, reject) = > {
        inquirer.prompt([
            {
                type: 'list'.name: 'version'.choices: ['patch'.'minor'.'major'].message: 'please choose argument [major|minor|patch]: '
            }
        ]).then(answer= > {
            resolve(answer.version);
        }).catch(err= > {
            reject(err);
        });
    });
};

const main = async() = > {const version = await getVersion();
    shell.echo(`\nReleasing ${version}. \n`);
    await shell.exec(`npm run standard-version -- --release-as ${version}`);
};

main();
Copy the code

Major: Upgrades the major version. Minor: upgrades the minor version. Patch: upgrades the patch version

6.5 to generate the CHANGELOG. Md

  • conventional-changelog-cliThe default recommended commit standard is from angular projects
  • parameter-i CHANGELOG.mdSays from theCHANGELOG.mdreadchangelog
  • Parameter -s indicates read and writeCHANGELOG.mdFor the same file
  • The -r parameter indicates the number of release versions required to generate Changelog. The default value is 1. All releases are 0
cnpm i conventional-changelog-cli -D
Copy the code
"scripts": {
    "changelogs": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
}
Copy the code

Eggs:

Have you seen a release like this on GithubIf you’re interested, here’s how to configure it. Okay

Install CNPM install gh-release -d

// package.json
 "scripts": {
    "rel": "gh-release"
  },
Copy the code

Operation steps:

  1. Commit the code using Git cz.
  2. Run the standard-version command to upgrade the version
  3. Generate md using Changelogs (note: do not commit code at this time)
  4. Run NPM run rel.

And you get the nice documentation that you have up here.

7. Continuous integration

There are many different solutions for continued integration and different ways to implement them: 1.Travis CI. 2 Jenkins, etc. Because the configuration is not complex, I will not expand it here. The specific configuration can be carried out together with operation and maintenance according to the situation of the company.

End !!!!