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 usedpreserve Keep JSX syntax, extension name.jsx React-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.ts Declaration 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.map file |
outFile | Whether to merge the output files into one file, the value is a file pathname, only setmodule The value ofamd andsystem Module 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 oftslib In the auxiliary tool function |
downlevelIteration | When the target isES5 orES3 When, for thefor-of ,spread anddestructuring Provides 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 allowthis The value of the expression isany Type 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, yesnode andclassic Two types,Detailed instructions |
baseUrl | Resolves the base directory for non-relative module names |
paths | Set module name to based onbaseUrl Path 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.json The 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 add
parserOptions
To 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
- 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 use
validate-commit-msg
tool
- You need to use
-
Unified Generation of Changelog documents
- use
conventional-changelog-cli
tool
- use
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-cli
The default recommended commit standard is from angular projects- parameter
-i CHANGELOG.md
Says from theCHANGELOG.md
readchangelog
- Parameter -s indicates read and write
CHANGELOG.md
For 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:
- Commit the code using Git cz.
- Run the standard-version command to upgrade the version
- Generate md using Changelogs (note: do not commit code at this time)
- 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 !!!!