Build front-end engineering

Build front-end engineering

Build front-end engineering

In our daily development projects, we basically use official scaffolding for development. Then using the official scaffolding development also has disadvantages: some functions cannot be customized well. Below I will summarize how I built a front-end project from scratch, and I hope it will be helpful to everyone.

1. The purpose of engineering

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

2. Process of engineering development

  • Compile => Pack (Merge) => Compress (webpack or rollup)
  • Code inspection => eslint
  • Test => jest
  • Outsourcing
  • Continuous inheritance

3. Selection of Compiler Tools

There are two major compilation tools, webpack and rollup respectively. Below we will explain how to configure them.

3.1 webpack configuration

const webpack = require ( "webpack" ); //html plug-in, 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 a built-in webpack-dev-server, if you need to install devServer separately for 5 and below : { hot : true , contentBase : path.join(__dirname, "dist" ), historyApiFallback : { index : "./index.html" , }, }, resolve : { extensions : [ ".ts" , ".tsx" , ".js" , ".json" ], alias : { "@" : path.resolve( "src" ), //After this configuration, @ can Point to the src directory }, }, module : { rules : [ { test : /\.tsx?$/ , loader: "ts-loader" } ], }, plugins : [ new HtmlWebpackPlugin({ template : "./src/index.html" }), //Built-in plugins for webpack. Hot update uses new webpack.HotModuleReplacementPlugin() ], }; Copy code

Note: webpack5 has built-in webpack-dev-server, which can be started directly with the webpack server command.

3.2 rollup configuration

Import ts from 'ROLLUP-plugin-typescript2' ; //insert resolve ts Import { nodeResolve } From '@ ROLLUP/plugin-the Node-Resolve' ; //parse third-party plug-in module Import CommonJS from '@ ROLLUP/plugin-CommonJS' ; //let third-party non-esm module support compiled Import json from 'ROLLUP-plugin -json ' ; //compiler support json Import serve from ' ROLLUP-plugin-serve ' ; //start local services plug- Import path from ' path ' //Distinguish 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 file sourcemap : true , //generate mapping file based on 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 analysis browser : true , extensions : [ '.js' , '.ts' ] }), ts({ tsconfig : path.resolve(__dirname, 'tsconfig.json' ) }), isDev? serve({ openPage : '/public/index.html' , contentBase : '' , port : 3000 }): null ] } Copy code

3.3 Compile the typescript file.

There are two schemes than your ts, one is compiled based on babel and the other is compiled based on tsc.

Compile based on tsc

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

Compile based on babel

Introduce babel plugins in webpack and rollup respectively

Babel's configuration file

const presets = [ [ '@babel/preset-env' , { //A preset collection //chrome, opera, edge, firefox, safari, ie, ios, android, node, electron //Combine targets and browerslist with the lowest version //enable A more compliant conversion, but the speed will be slower. The default is `false`. From the current point of view, it is a more stringent conversion, including some code checks. spec : false , //There are two modes: normal, loose. Among them, normal is closer to es6 loose and closer to es5 loose : false , //"amd" | "umd" | "systemjs" | "commonjs" | "cjs" | false, defaults to "commonjs" modules : false , //means esm module //Print plug-in usage debug : false , useBuiltIns : 'usage' , //Introduce corejs as needed : { 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 delete this plugin //support decorator mode development [ '@babel/plugin-proposal-decorators' , { 'legacy' : true }], [ '@babel/plugin-proposal-class-properties' , { 'loose' : true }], ]; module .exports = { presets, plugins }; Copy code

Suggestion: It is recommended to use babel to compile webpack in business development. Edit the js library to use tsc to compile.

3.4 ts configuration file combing

Basic parameters

parameterExplanation
targetUsed to specify the version target after compilation
moduleGenerated module form: none, commonjs, amd, system, umd, es6, es2015 or esnext. Only amd and system can be used with outFile. When target is es5 or lower, es6 and es2015 are available
libES function libraries introduced at compile time include: es5, es6, es7, dom, etc. If not set, the default is: When target is es5: ["dom", "es5", "scripthost"] When target is es6: ["dom", "es6", "dom.iterable", "scripthost"]
allowJsWhether to allow JS files to be compiled, the default is false, that is, JS files are not compiled
checkJsWhether to check and report errors in the JS file, the default is false
jsxSpecify the development environment for jsx code
preserve
Refers to retain the JSX syntax, the extension is
.jsx
, react-native means to retain jsx syntax, extension js, react refers compiled into ES5 syntax Detailed
declarationWhether to generate the corresponding
.d.ts
Declaration file
declarationDirThe generated .d.ts file storage path, the default is the same as the .ts file
declarationMapWhether to generate a map file for the declaration file .d.ts
sourceMapWhether to generate at compile time
.map
file
outFileWhether to merge the output files into one file, the value is a file path name, only setting
module
The value is
amd
with
system
This configuration is only supported when the module
outDirSpecify output folder
rootDirThe root directory of the compiled file, the compiler will look for the entry file in the root directory
compositeWhether to compile and build the reference project
removeCommentsWhether to delete the comments in the compiled file
noEmitDo not generate compiled files
importHelpersWhether to introduce
tslib
Auxiliary tool functions
downlevelIterationWhen target is
ES5
or
ES3
for-of
,
spread
with
destructuring
Iterators in provides full support
isolatedModulesSpecify whether to treat each file as a separate module, the default is true

Strict inspection **

parameterExplanation
strictWhether to start all type checks
noImplicitAnyThe default any type is not allowed
strictNullChecksWhen set to true, null and undefined values cannot be assigned to values other than these two types
strictFunctionTypesWhether to use function parameter two-way covariance check
strictBindCallApplyWhether the detection of the parameters of the methods bound by bind, call and apply is strictly tested
strictPropertyInitializationCheck whether the non-undefined properties of the class have been initialized in the constructor
noImplicitThisNot allowed
this
The value of the expression is
any
When type
alwaysStrictSpecifies to always check every module in strict mode

Additional inspection **

parameterExplanation
noUnusedLocalsCheck if there are variables defined but not used
noUnusedParametersCheck if there are any parameters that are not used in the function body
noImplicitReturnsCheck if the function has a return value
noFallthroughCasesInSwitchCheck if there is a case in the switch without using break to jump out

Module analysis check **

parameterExplanation
moduleResolutionSelect module analysis strategy, there are
node
with
classic
Two types, detailed description
baseUrlBase directory for parsing non-relative module names
pathsSet the module name to based on
baseUrl
Path mapping
rootDirsYou can specify a path list, and the compiler will put the contents of the paths in this path list into a folder when building
typeRootsSpecify the path list of declaration files or folders
typesUsed to specify the modules that need to be included
allowSyntheticDefaultImportsAllow default import from modules that do not have default export
esModuleInteropCreate a namespace for imported content to achieve mutual access between CommonJS and ES modules
preserveSymlinksDo not resolve symbolic links to their real paths

sourcemap check **

parameterExplanation
sourceRootThe debugger should find the TypeScript file instead of the source file location
mapRootThe debugger finds the location of the map file instead of the generated file, and specifies the root path of the map file
inlineSourceMapSpecify whether to compile the contents of the map file and the js file in the same js file
inlineSourcesWhether to further include the content of the .ts file into the output file

** Experimental Options **

parameterExplanation
experimentalDecoratorsWhether to enable the experimental decorator feature
emitDecoratorMetadataWhether to provide metadata support for the decorator

Test options

parameterExplanation
filesConfigure an array list, which contains the relative or absolute path of the specified file, the compiler will only compile the files listed in the files when compiling
includeinclude can also specify a list of paths to be compiled, but the difference with files is that the path here can be a folder or a file
excludeexclude means files to be excluded and not compiled, he can also specify a list
extendsextends can inherit the configuration in this configuration file by specifying a path to another tsconfig.json file
compileOnSaveWhen we edit and save the file in the project, the editor will
tsconfig.json
Configuration regenerate file
referencesAn array of objects, specifying the items to be referenced

Basic configuration of tsconfig.json

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

The ts configuration file is sorted out.

4. Code Verification

4.1 Purpose of code inspection:

  • Standardized code can promote teamwork
  • Standardized code can reduce maintenance costs
  • Standardized code helps code review (code review)

4.2 Common code specification documents

4.3 Code and inspection plug-in eslint (vscode)

Search for eslint in the vscode store, then install

Configuration effective method 1: (modify vscode configuration)

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

Method 2: Add configuration files to each individual project

4.4 Install the module

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

4.5 Basic configuration

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 code

4.6 Code and inspection

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 code

5. Unit Testing

5.1 Installation and configuration

cnpm i jest @types/jest ts-jest jest -D //dependent package npx ts-jest config:init //generate configuration file //package.json "scripts" : { + "jest-test" : "jest -o" , + "jest-coverage" : "jest --coverage" }, Copy 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 code

Note: Here is just a brief list of the things needed, and a sufficient configuration. If you want to configure it according to specific needs, you need to check the documentation.

6. git submission specification and changelog (package delivery)

6.1 Advantages

  1. Good git commit benefits
  • Can speed up the code review process
  • The changelog can be generated based on the metadata of git commit
  • Let other developers know the reason for the modification

6.2 Good commit

  • commitizen is a tool for formatting commit messages

  • validate-commit-msg used to check the project

    Commit message
    Conform to the format

  • conventional-changelog-cli can be downloaded from

    git metadata
    Generate change log

  • Unified team's git commit standard

  • can use

    angular
    of
    git commit
    Log as a basic specification

    • The type of submission is restricted to feat, fix, docs, style, refactor, perf, test, chore, revert, etc.
    • The submission information is divided into two parts, the title (the first letter is not capitalized, no punctuation at the end), and the main content (description of the modified content)
  • Log submission friendly type selection prompts to use the commitize tool

  • A mechanism to ensure that logs that do not meet the required format are rejected

    • Need to use
      validate-commit-msg
      tool
  • Unified changelog document information generation

    • use
      conventional-changelog-cli
      tool
cnpm i commitizen validate-commit-msg conventional-changelog-cli -D commitizen init cz-conventional-changelog --save --save-exact git cz Copy code

Use the git cz command: it can be very convenient to operate.

6.3 Format of submission

<type>(<scope>):<subject/> <BLANK LINE> <body> <BLANK LINE> <footer> Copy code
  • Represents the type of a certain submission, such as fixing bugs or adding features
  • Represents scope, such as a page or a component
  • Subject, summarizing the content of this submission
  • Detailed impact content
  • Fixed bugs and issue links
Types ofmeaning
featNew feature
fixFix bug
docsOnly modified documents, such as README, CHANGELOG, CONTRIBUTE, etc.
styleOnly modify the space, format indentation, preference and other information, without changing the code logic
refactorCode refactoring, no new features or bug fixes
perfOptimize related, improve performance and experience
testTest cases, including unit tests and integration tests
choreChange the build process, or add dependent libraries and tools
revertRoll back to the previous version
ciCI configuration, script files, etc. update

6.4 Upgrade package.json version

Installation depends on cnpm install standard-version inquirer shelljs -D

Execute the script:

const inquirer = require ( 'inquirer' ); //command line interactive 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 code

major: upgrade the major version minor: upgrade the minor version patch: upgrade the patch version

6.5 Generate CHANGELOG.md

  • conventional-changelog-cli
    The default recommended commit standard is from the angular project
  • parameter
    -i CHANGELOG.md
    Means from
    CHANGELOG.md
    Read
    changelog
  • Parameter -s means read and write
    CHANGELOG.md
    For the same file
  • The parameter -r represents the number of release versions that need to be used to generate the changelog, the default is 1, and all are 0
cnpm i conventional-changelog-cli -D duplicated code
"scripts": { "changelogs": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0" } Copy code

Easter eggs:

Have you seen such a release document on github If you are interested, the following will teach you how to configure

Cnpm install gh-release -D

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

Steps:

  1. Use git cz to submit the code.
  2. Use standard-version to upgrade the version
  3. Use changelogs to generate md (note: do not submit code at this time)
  4. Execute npm run rel.

You can get the good-looking documents above.

7. Continuous Integration

Continue to integrate There are many different solutions, implementations also have different ways:. 1 Travis CI  . 2 jenkins and so on. Since the configuration is relatively uncomplicated, I won't go into it here. The specific configuration can be carried out together with the operation and maintenance according to the company's situation.

the end! ! ! !