Writing in the front

Small vegetable chicken of I again to record notes, this is the front end engineering, feel now the front end can do a lot of things, not only before writing the page cut diagram son. You can add, delete and modify the editor, page and the server side. It is not limited to the Web side, but also involved in app, desktop and server side. This time I learned the knowledge of Webpack and summarized the following notes

Front-end engineering





1. Introduction to engineering

Project according to business characteristics

  • standardized

  • modular

  • tools

  • automation

  • Front end separation

It mainly includes technology selection, code specification, construction and release scheme for different business scenarios. The main purpose is to improve the development efficiency and code quality of front-end development engineers, reduce the communication cost of front-end and back-end joint debugging, and enable front-end and back-end engineers to focus more on their own areas of expertise.

2. Scaffolding

2.1. Why do scaffolds/scaffolds solve problems

In recent years, the front-end has been developed from simple static web applications to the desktop, mobile, server and complex Web pages. Many of these projects are faced during the creation and writing phases

  • Same organizational structure

  • Same development paradigm

  • Same module dependencies

  • Same tool configuration

  • Same basic code

Based on the above problems, scaffolding came into being. The significance of its emergence is to solve the above problems.

2.2, yeoman

Introduction of 2.2.1,

  • The old scaffolding tool can be used during project creation or during project development (Sub Generator).

2.2.2 Use summary

  • Identify the requirements and find the appropriate generator

  • Install the generator globally

  • Run the generator through YO

  • Enter interaction options through the command line

  • Generate the required directory structure

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — –

2.2.3. Use published generators

  • Global installation

  • yarn -g add yo

  • Installation of the generator package

  • Yarn add generator-node (note: Yeoman’s generator is in the form of generator- XXX)

Mkdir XXXCD xxxyo node Enter the commands interactivelyCopy the code

2.2.3 customize the GENERATOR

  • Create the project folder and initialize the project

  • Install the Generator provided by Yeoman. The custom generator is based on the official generator implementation.

  • Create the generator/app/index. Js

  • After you customize the configuration, publish it globally

  • To use the generator name, simply yo the generator name

  • Publish to the NPM platform

mkdir generator-wc-vuecd generator-wc-vueyarn init code .//phpstorm64 .yarn add yoyarn add yeoman-generator - create generators/app/dev index. Jsyeoman - the generator a custom generator for template, create app/templates, Add yarn link //link to the global mkdir wc-vuecd wc-vueyo wc-vue If you run the command, an error message is displayed. Gitignore is not generated.Copy the code

Note: The names of files in templates need to be replaced by ejS templates.

If <%%> is encountered in the template input, need to output unchanged, as long as <%% %> add a %

// A custom generator inherits the officially provided generator module to generate const generator = require('yeoman-generator'Module. Exports = class extends Generator {// command line interactionprompting() {        return this.prompt([            {                type: 'input'// Input type name:'name',// key                message: 'your project name ',// prompt default: this.appName // Folder name by default}]). Then (Answers => {this.answers = answers // Store variables after the interaction result, use the following})}writing() {const templates = [// custom template path'.browserslistrc'.'.editorconfig'.'.env.development'.'.env.production'.'.eslintrc.js'.'.gitignore'.'babel.config.js'.'package.json'.'postcss.config.js'.'README.md'.'public/favicon.ico'.'public/index.html'.'src/App.vue'.'src/main.js'.'src/router.js'.'src/assets/logo.png'.'src/components/HelloWorld.vue'.'src/store/actions.js'.'src/store/getters.js'.'src/store/index.js'.'src/store/mutations.js'.'src/store/state.js'.'src/utils/request.js'.'src/views/About.vue'.'src/views/Home.vue'Templates. ForEach (item => {// go through the path this.fs.copyTpl(// print this.templatepath (item), // Template file path this.destinationPath(item),// output path this.answers// use the resulting command line interaction as context)})}}Copy the code

Publish to the NPM platform

  • Login NPM is required for the first release

  • If it is not the first time you can directly NPM publish

NPM login or YARN login If an incorrect account name is entered but NPM or YARN remembers it, yarn can be usedlogoutOr NPM logoutnpm publishCopy the code

2.3, the plop

2.3.1, introduction,

  • To summarize, PLOP is a small generator for generating specific directory structures in a project

2.3.2, use,

  • Select the file you want to use

  • Install the plop

  • Create a PLOP entry file

  • Example Create a plop template folder

  • Run the plop

cdXxxmkdir plopfile.js Configure plopmkdir plop-templateyarn plopCopy the code
    module.exports = function(plop) {// Create your generators here'addComp', {// Generator name description:'this is a addComp'Prompts. [//CMD interactive {type:'input',                    name:'name'// Use message as key in ejS templates:'this is comp name,the first letter must enter upper',                    default:'Order'Prompts. Prompt. Prompt. [{prompt.type:'add'// The required action path:'src/components/{{name}}/{{name}}.jsx'// Export path templateFile:'plop-template/component.hbs'// template path}, {type:'add',                    path:'src/components/{{name}}/style.module.scss',                    templateFile:'plop-template/style.module.scss.hbs'                },            ]  // array of actions        });    };​Copy the code

3. Automated build tools

3.1. What are automated Build tools

Front-end automation is a very broad and complex engineering problem, which I divide into three categories:

  • Automated Build (development)

  • Automated Testing (Development & Testing)

  • Automated publishing

An automated build is the process of automatically converting source code into a target that users can use using tools. ‘Target’ here refers to a collection of JS, CSS, and HTML. The ‘user’ can be you, the test, or a real user.

These tools save time by enabling us to work at a higher level and automate repetitive tasks; Tools simplify our workflow, allowing us to focus on creative work instead of wasting hours on tedious tasks. With gulp, for example, we can have it listen for changes in each source file, and once you press CTRL + S, it will automatically display the new changes in the browser.

These tools make up a system that can be called a build system. And these tools can be called automated build tools, which are essentially plug-ins or scripts that perform tedious and error-prone tasks in place of people.

3.2. Why use automated build tools

In a word: Automation. For repetitive tasks, such as minification, compilation, unit testing, linting, etc., automated tools can ease your effort and simplify your work. Once you have properly configured tasks in the build tool, the task runner will automatically do most of the boring work for you or your team.

3.3. Automated Build tools

3.3.1, GRUNT

1, the introduction of

The old automated build tool, as it’s officially called. All the repetitive tasks you can think of in Grunt you can do with plug-ins.

2, installation,
  • yarn add grunt

3, use,
  • Type nul>gruntfile.js // configuration entry

  • Configure correct options

  • Yarn Grunt Task name

4, configuration,
4.1. Basic usage and error throwing
/ * TODO: 3. Export a function. 4. This function takes a parameter of the grunt object type. 5 Module. exports=grunt=>{// register a grunt synchronization task grunt.'foo',()=>{        console.log('hello grunt')}); grunt.registerTask('bar'.'description',()=>{        console.log('test')}); Grunt. RegisterTask (grunt. RegisterTask (grunt. RegisterTask (grunt.'default'['foo'.'bar'] // Other tasks can also be performed in the task function grunt. RegisterTask ('run-other', () => {// Foo and bar automatically execute grunt. Task.run () after the current task is completed.'foo'.'bar')        console.log('current task runing~'}) // The default grunt is encoded in synchronous mode // If asynchron is required, the callback can be created using this.async().'async-task'.function () {        const done=this.async()        setTimeout(()=>{            console.log('hello, asyncTask');            done()}, 1000)}) / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- / / throw an error of grunt. RegisterTask ('wrong',()=>{        console.log('hello ,wrong')        return false}) // The way to mark the failure of the current task in asynchronous functions is to specify one for the callback functionfalseThe argument of grunt. RegisterTask ('bad-async'.function () {        const done = this.async()        setTimeout(() => {            console.log('async task working~')            done(false)}, 1000)}) // Grunt. RegisterTask (grunt.'wrongTaskQueue'['foo'.'wrong'.'bar'])​}Copy the code
4.2 Config Configuration
Module.exports =grunt=>{// grunt. InitConfig () used to add configuration options for tasks grunt.'baz'        }    })    grunt.registerTask('foo', () => {// You can use grunt. Config () to get configuration console.log(grunt. Config ()).'foo'Console. log(grunt. Config () console.log(grunt.'foo.bar'))})}Copy the code
4.3. Multiple goals
Module. exports=grunt=>{// multiobject mode, which allows tasks to be configured as subtasks grunt. InitConfig ({build: {options: {MSG:})'task options'            },            foo: {                options: {                    msg: 'foo target options'                }            },            bar: '456'        }    })    grunt.registerMultiTask('build'.function () {        console.log(this.options());    })}​Copy the code
4.4 Common plug-ins
const sass=require('sass')const loadGruntTasks=require('load-grunt-tasks'Module.exports = grunt => {// grunt. InitConfig () is used to add configuration options grunt //sass-> CSS sass: {options:{// In addition to configuration path accident also need to add implementation module. implementation:sass,sourceMap:true}, main: {files: {// Key-value pair form, key is the input, value is the input path'dist/css/main.css': 'src/scss/main.scss'                }            }        },        //newEcmaScript=>oldEcmaScript        babel:{            options:{                presets:['@babel/preset-env'].sourceMap:true            },            main:{                files:{                    'dist/js/app.js':'src/js/app.js'                }            }        },        watch:{            js:{                files:['src/js/*.js'],                tasks:['babel']            },            css:{                files:['src/scss/*.scss'],                tasks:['sass']}}}); LoadGruntTasks (grunt) loadGruntTasks(grunt. LoadNpmTasks (grunt.'grunt-sass') // The default task is to compile and then listen. grunt.registerTask('default'['sass'.'babel'.'watch'])}​Copy the code
5. Use summaries
  • The installation

  • Download the plugin

  • Import plug-ins (note: Can be automatically imported using load-grunt- Tasks)

  • Configuration option

  • Start the grunt

3.3.2 rainfall distribution on 10-12, GULP

1, the introduction of

Plug-in support, high degree of customization, easy configuration, read and write in the form of flow automation build tools

2, installation,
// Install gulp command line tool NPM install --global gulp-cli// Install gulp project depends on NPM install --save-dev gulpCopy the code
3, use,

Before using gulp, it is important to know that tasks in Gulp are asynchronous by default, which is quite different from Grunt.

Mkdir gulp-testcd gulp-testtype nul> gulpfile.js // Create gulpfile as a configuration file entryCopy the code
4, configuration,
Create a task
exports.foo=(done)=>{// Default is asynchronous, and grunt defaults to synchronous console.log('foo task wroking');    done() // Manually use the callback to complete the task}; / / the default taskexports. Default =done=>{    console.log( 'end default')    done(a)}; Const gulp=require(gulp=require(gulp=require(gulp=require()))'gulp')gulp.task('bar'.done=>{    console.log('old gulp');    done()})Copy the code
Manually throwing errors
const fs=require('fs')exports.callback=done=>{    console.log('callback');    done()}exports.callback_error = done => {    console.log('callback task')    done(new Error('task failed'))}exports.promise = () => {    console.log('promise task')    return Promise.resolve()}exports.promise_error = () => {    console.log('promise task')    return Promise.reject(new Error('task failed'))}const timeout = time => {    return new Promise(resolve => {        setTimeout(resolve, time)    })}exports.async = async () => {    await timeout(1000)    console.log('async task')}​Copy the code
Read, write, and pipe
Exports.stream = () => {// // read stream // constread=fs.createReadStream('yarn.lock') // // // const write= fs.createWritestream ('a.txt') // // through the pipe link // read-.pipe (write) // // output stream //return readreturn src('yarn.lock')        .pipe(rename('a.txt'))        .pipe(dest('text'))}Copy the code

Demo can use the fs module of Node to read and write data, or use the SRC, Pipe, and dest built-in data of gulp. Rename is a gulp plug-in

  • yarn add gulp-rename –dev

  • const rename=require('gulp-rename')Copy the code
  • pipe(rename(‘a.txt’))

src()

Create a stream to read Vinyl objects from the file system.

Vinyl

Virtual file format. When SRC () reads the file, a Vinyl object is generated to represent the file — including path, content, and other metadata.

Vinyl objects can be transformed using plug-ins. You can also persist them to the file system using dest().

When creating your own Vinyl objects — rather than generating them using SRC () — use external Vinyl modules, as shown in the usage below.

dest()

Create a stream for writing Vinyl objects to the file system.

The demo application
// Implement the project build task const del = require('del')const browserSync = require('browser-sync'//gulp-load-plugin const loadPlugins = require('gulp-load-plugins')const plugins = loadPlugins(); const {src, dest, parallel, series, watch} = require('gulp'Const bs = browserSync.create(); // return the current working directory of the command line const CWD =process.cwd(); // Configure the project pathlet config={    build:{        src:'src',        dist:'dist',        temp:'temp',        public:'public',        paths:{            styles:'assets/styles/*.scss',            scripts:'assets/scripts/*.js',            pages:'*.html',            images:'assets/images/**',            fonts:'assets/fonts/**'},}}try{// loadConfig=require('${cwd}/pages.config.js') config= object.assign ({},config,loadConfig)}catch(e){}const clean = () => {//del can be configured with multiple targets and can be covered with [].return del([config.build.dist,'temp'])}const style = () => {// Output according to directory structurereturn src(config.build.paths.styles, {base: config.build.src,cwd:config.build.src})        .pipe(plugins.sass({outputStyle: 'expanded'}))        .pipe(dest(config.build.temp))        .pipe(bs.reload({stream:true})) /* TODO: * 1, yarn add gulp-sass * 2,.pipe(plugins.sass()) * 3, SCSS files starting with _ are considered dependencies, * */}const script = () => {//yarn add gulp-babel --dev //yarn add @babel/core --dev //yarn add @babel/preset-env --devreturn src(config.build.paths.scripts, {base: config.build.src,cwd:config.build.src})        .pipe(plugins.babel({presets: [require('@babel/preset-env')]}))        .pipe(dest(config.build.temp))        .pipe(bs.reload({stream:true}))}​const page = () => {    //yarn add gulp-swig --dev    return src(config.build.paths.pages,{base: config.build.src,cwd:config.build.src})        .pipe(plugins.swig({data:config.data}))        .pipe(dest(config.build.temp))        .pipe(bs.reload({stream:true}))}​const image = () => {    returnsrc(config.build.paths.images, {base: config.build.src,cwd:config.build.src}) .pipe(plugins.imagemin()) .pipe(dest(config.build.dist))}; const font = () => {returnsrc(config.build.paths.fonts, {base: config.build.src,cwd:config.build.src}) .pipe(plugins.imagemin()) .pipe(dest(config.build.dist))}; const extra = () => {return src('* *', {base: config.build.public,cwd:config.build.src}) .pipe(dest(config.build.dist))}//yarn add browser-sync--devconst serve = () => { watch(config.build.paths.styles, {cwd:config.build.src},style) watch(config.build.paths.scripts,{cwd:config.build.src}, Script) watch (config. Build. Paths. Pages, {CWD: config. Build. SRC}, page) / / centralized monitoring, reload watch([ config.build.paths.images, config.build.paths.fonts, ], {cwd:config.build.src},bs.reload) watch('* *',{cwd:config.build.public},bs.reload)    // watch('src/assets/images/**', image)    // watch('src/assets/fonts/**', font)    // watch('public/**', extra) bs.init({// Whether the connection is successful notify:false,        // port:2099,        // open:false// monitor file changes // files:'dist/**'Server: {/ / web root directory baseDir: [config. Build. Temp, config. Build. Dist, config. Build. Public], routes: {/ / routing configuration due to the root directory'/node_modules': 'node_modules'            }        }    })​}const useref=()=>{    //yarn add gulp-useref --dev    return src(config.build.paths.pages,{base:config.build.temp, cwd :config.build.temp})        .pipe(plugins.useref({ searchPath: [config.build.temp, '. '})) //  yarn add gulp-if --dev //yarn add gulp-uglify gulp-clean-css gulp-htmlmin --dev .pipe(plugins.if(/\.js$/, plugins.uglify())) .pipe(plugins.if(/\.css$/, plugins.cleanCss())) .pipe(plugins.if(/\.html$/, Plugins.htmlmin ({// Collapse HTML interior Spaces, CSS, js collapseWhitespace:true,            minifyCSS: true,            minifyJS: true        })))        .pipe(dest(config.build.dist))}const compile = parallel(style, script, page)const build = series(clean, parallel(series(compile,useref),    font,    image,    extra))const develop=series(compile,serve)module.exports = {    build, develop,clean,useref}​Copy the code

use

yarn linkcd demoyarn link 'order-gulp'/ / package. Name the customtype nul>gulpfile.jsmodule.exports=require('orderGulpToNpm') yarn gulp build / / throw the task can be called -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- or by NPM install yarn add order - gulpCopy the code
conclusion
  • Easy to use: Using code over configuration, Gulp makes simple things simple and complex tasks manageable.

  • Efficient: Build faster by taking advantage of Node.js’ powerful streams and eliminating the need to write intermediate files to disk.

  • High quality: Gulp’s strict plug-in guidelines ensure that plug-ins are simple and work the way you expect them to.

  • Easy to learn: By keeping the API to a minimum, you can learn Gulp in a very short time. The build is just what you would expect: a series of flow pipes.

4. Modularization

4.1 modular specification, ES MODULE matters needing attention

// Importing a member is not a copy, but a direct import of the reference address of the module memberexportThe imported variables are the same space in memory. // Import module member variables are read-only // name ='tom'// an error is reported // But note that if an object is imported, the read and write properties of the object are not affected // name.xxx ='xxx'/ / normalCopy the code

5, modular implementation

5.1, webpack

5.1.1, introduction,

In essence,

webpack
Static Module Bundler
Dependency Graph
bundle

5.1.2 What problems/functions have been solved

  • In production, compress the code volume as much as possible to reduce the project size and speed up rendering

  • In the development environment, use various auxiliary functions to improve the development experience

5.1.3 Basic configuration of WEBPACK

  • The entrance (entry)

  • Output (output)

  • loader

  • The plug-in (plugins)

The entrance (ENTRY)

The entry point indicates which module webPack should use to build its interior

Dependency graph

Each dependency is then processed and finally output to called

bundles

You can specify an entry starting point (or multiple entry starting points) by configuring the Entry property in the Webpack configuration. The default value is./ SRC.

Let’s look at the simplest example of an Entry configuration:

webpack.config.js

module.exports = {  entry: './path/to/my/entry/file.js'};Copy the code
Exports (OUTPUT)

Does the Output property tell WebPack where to output what it has created

bundles

./dist
output

webpack.config.js

const path=require('path')module.exports={    // mode:'development',    //    entry:'./src/index.js'Output :{filename:'bundle.js',        path:path.join(__dirname,'dist') // Exit requires an absolute path publicPath:'dist/'// Public directory}}Copy the code
LOADER

loader

The module

In essence, WebPack Loader converts all types of files into modules that the application’s dependency diagram (and ultimately its bundle) can reference directly.

Note that loader can import any type of module (such as.css files), which is unique to WebPack and may not be supported by other packers or task executors. We think this language extension is necessary because it allows developers to create more accurate dependency diagrams.

At a higher level, loader has two goals in the webpack configuration:

  1. The test property identifies the files or files that should be converted by the corresponding loader.

  2. The use attribute indicates which loader should be used for conversion.

css-loader/style-loader

Embed CSS as JS code

const path = require('path')module.exports = {    mode: 'none',    entry: './src/main.css'Output: {filename:'main.js',        path: path.join(__dirname, 'dist'}, module: {rules: [{test: /.css$/,                use: [                    'style-loader'.'css-loader'}}}}}}}}}}}}Copy the code
babel-loader

Convert the latest es features to ES5

test: /.js$/,    use: {        loader: 'babel-loader',            options: {                presets: ['@babel/preset-env']}}},Copy the code
file-loader/url-loader

File-loader converts files into JS resources that can be imported

Url-loader converts a file to a data-URL format

test: /.png$/,use: {        loader:'url-loader'// Load resources in data-URL mode, suitable for small static resources options:{limit:10 x 1024// If the value exceeds 10 KB, file-loader is used. Note that file-loader must be installed. }}}Copy the code
html-loader

Handles incoming tags within HTML

{    test:/.html$/,        use:{            loader:'html-loader',                options:{                    attrs:['img:src'.'a:href']// HTML index. By default, only img SRC is configured. If you need to add resources, add them as string keys. }}},Copy the code
Custom loader

webpack.config.js

{    test: /.md$/,        use: [            'html-loader'// It is important to note that the parsed data must be js code, so it needs to be processed by htML-loader'./markdown-loader'}}};Copy the code

maridown-loader

const marked=require('marked'//md syntax processing module. module.exports=source=>{const html=marked(source)    return html}​Copy the code
The plug-in (PLUGINS)

Loaders are used to transform certain types of modules, while plug-ins can be used to perform a wider range of tasks. Plug-ins range from packaging optimization and compression to redefining variables in the environment. Plug-in interfaces are extremely powerful and can be used to handle a wide variety of tasks.

To use a plugin, you simply require() it and add it to the plugins array. Most plug-ins can be customized with options. You can also use the same plug-in multiple times for different purposes in a configuration file by using the new operator to create an instance of it.

clean-webpack-plugin

Clearing output directory files is used in the production environment

const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const webpackConfig = {    plugins: [        /**         * All files inside webpack's output.path directory will be removed once, but the * directory itself will not be. If using webpack 4+'s default configuration,         * everything under <PROJECT_DIR>/dist/ will be removed.         * Use cleanOnceBeforeBuildPatterns to override this behavior.         *         * During rebuilds, all webpack assets that are not used anymore         * will be removed automatically.         *         * See `Options and Defaults` for information         */        new CleanWebpackPlugin(),    ],};Copy the code
html-webpack-plugin

Automatically generate HTML files and import corresponding resources

const path = require('path')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')​module.exports = {    mode: 'none',    entry: './src/main.js',    output: {        filename: 'bundle.js',        path: path.join(__dirname, 'dist'),        // publicPath: 'dist/'// The project root directory, which is already created automatically by Webpack, so there is no need to specify the root directory here. }, ************ plugins: [// to generate index.html new HtmlWebpackPlugin({title:'Webpack Plugin Sample',            meta: {                viewport: 'width=device-width'            },            template: './src/index.html',            filename:'1.html'HTML new HtmlWebpackPlugin({filename:'about1.html'}})]Copy the code

HTML – the plugin template

index.html

<! DOCTYPE html> <html> <head> <meta charset="utf-8"/>            <title><%= htmlWebpackPlugin.options.title %></title>        </head>        <body></body>    </html>Copy the code
copy-webpack-plugin

Copy static resources intact, usually used in production environments, except array but this is obj. Pay attention to

const CopyPlugin = require('copy-webpack-plugin')const webpackConfig = {    plugins: [        /**         * All files inside webpack's output.path directory will be removed once, but the * directory itself will not be. If using webpack 4+'s default configuration,         * everything under <PROJECT_DIR>/dist/ will be removed.         * Use cleanOnceBeforeBuildPatterns to override this behavior.         *         * During rebuilds, all webpack assets that are not used anymore         * will be removed automatically.         *         * See `Options and Defaults` for information         */           new CopyPlugin([{              from: 'public/**'// With folder output. }]) /* new CopyPlugin(['public'*/],};Copy the code
define-webpack-plugin

Provide a global variable at packaging time

const webpack = require('webpack')const webpackConfig = {    plugins: [        /**         * All files inside webpack's output.path directory will be removed once, but the * directory itself will not be. If using webpack 4+'s default configuration,         * everything under <PROJECT_DIR>/dist/ will be removed.         * Use cleanOnceBeforeBuildPatterns to override this behavior.         *         * During rebuilds, all webpack assets that are not used anymore         * will be removed automatically.         *         * See `Options and Defaults` for information         */        new webpack.DefinePlugin({            test:JSON.stringify('dsadas')// Provide a global variable at package time})],};Copy the code

5.1.4 ensuring, DEVSERVER

yarn add webpack-dev-server -DCopy the code

Can be used as a proxy for cross-domain requests,

  devServer: {    contentBase: './public',    proxy: {      '/api': {        // http://localhost:8080/api/users -> https://api.github.com/api/users        target: 'https://api.github.com',        // http://localhost:8080/api/users -> https://api.github.com/users        pathRewrite: {          '^/api': ' '}, // do not use localhost:8080 as the host name for requesting GitHub changeOrigin:true}}}Copy the code

ContentBase Static resource directory proxy proxy ‘/ API ‘Request starting with API Target Proxy address pathRewrite Remove API changeOrigin change host name

5.1.5. HMR Hot Swap

webpack.config.js

const webpack = require('webpack')const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {  mode: 'development',  entry: './src/main.js',  output: {    filename: 'js/bundle.js'  },  devtool: 'source-map',  devServer: {    hot:trueModule. hot // hotOnly:true// Plugins: [new HtmlWebpackPlugin({title:'Webpack Tutorial',      // template: './src/index.html'}), new webpack HotModuleReplacementPlugin () / / on webpack own start hot drawing plugin]}Copy the code

main.js

//work stream.if (module.hot) {    let lastEditor = editor    module.hot.accept('./editor.js'.function (e) {        const value=lastEditor.innerHTML        document.body.removeChild(lastEditor)        const newEditor=createEditor()        newEditor.innerHTML=value        document.body.appendChild(newEditor)        lastEditor=newEditor    })    module.hot.accept('./better.png',()=>{        img.src = background        console.log(background)    })}Copy the code

5.1.6, DEVTOOL

sourceMap

  • ‘cheap-module-eval-source-map’,

  • Development mode usually uses this to locate the line and to locate the code before compilation

  • none

  • Production mode does not require sourceMap. If you do, you can select ‘nosource-source-map’ to see the error message and column count, but sourceMap is not produced to prevent source code leakage

5.1.7 run

Zero configuration operation

Yarn webpack webpack -cli-dyarn webPackYARN webpack --mode-production// Production mode YARN webpack --mode-noneyarn webpack --mode-development// yarn webpack-dev-server // Start devServerwebPack by default, the root directory is used as the entry file and the output file is compressed to the dist directory.Copy the code

5.1.8, MODE,

As the project grows larger, it becomes important to have different configurations for different modes. So we’re going to build the general program

  • Webpack.common. js //dev and prod common configuration

  • webpack.dev.js

  • webpack.prod.js

common

const HtmlWebpackPlugin = require('html-webpack-plugin')​module.exports = {  entry: './src/main.js',  output: {    filename: 'js/bundle.js'  },  module: {    rules: [      {        test: /\.css$/,        use: [          'style-loader'.'css-loader'] {},test: /\.(png|jpe? g|gif)$/, use: { loader:'file-loader',          options: {            outputPath: 'img',            name: '[name].[ext]'          }        }      }    ]  },  plugins: [    new HtmlWebpackPlugin({      title: 'Webpack Tutorial',      template: './src/index.html'}})]Copy the code

dev

const common=require('./webpack.common')const merge = require('webpack-merge')const webpack=require('webpack')​module.exports=merge(common,{    mode:'development',    devtool: 'cheap-eval-module-source-map',    devServer:{        hot:true,        contentBase:'public'    },    plugins:[        new webpack.HotModuleReplacementPlugin()    ]})​Copy the code

prod

const common=require('./webpack.common')const merge = require('webpack-merge')const webpack=require('webpack')const CopyWebpackPlugin=require('copy-webpack-plugin')const {CleanWebpackPlugin}=require('clean-webpack-plugin')module.exports=merge(common,{    mode:'production',    devtool:false,    plugins:[        new CleanWebpackPlugin(),        new CopyWebpackPlugin(['public'])]})Copy the code

Specify the corresponding file when packaging.

It can also be written in package.json via scripts

"build": "webpack --config webpack.prod.js"."dev": "webpack --config webpack.dev.js"Copy the code

5.1.9, TREESHAKING

Flags unused or useless code

module.exports = {  mode: 'none',  entry: './src/index.js',  output: {    filename: 'bundle.js'  },  module: {    rules: [      {        test: /\.js$/,        use: {          loader: 'babel-loader',          options: {            presets: [                '@babel/preset-env'// If Babel has already converted ESM, Tree Shaking is invalid // ['@babel/preset-env', { modules: 'commonjs'}] / ['@babel/preset-env', { modules: false}] // You can also use the default configuration, i.e. Auto, so that babel-loader automatically closes ESM conversion // ['@babel/preset-env', { modules: 'auto'}}}}}}}, optimization: {}}}}true, // Whenever possible, combine each module into a function concatenateModules:true// Compress the output to minimize:true  }}​Copy the code

5.1.10, SIDEEFFECT

Side effects, useless modules

webpack.config.js

optimization: {    sideEffects: true// Module exports only used members // usedExports:true, // merge each module into a function whenever possible // concatenateModules:true// Compress the output // minimize:true,}Copy the code

package.json

  "sideEffects": [     "./src/extend.js"."*.css"  ] "sideEffects": falseIf it is determined that there is no side effect code in the project, simply identify all asfalseCan beCopy the code

Side effects module

import { Button } from './components'// The style file belongs to the side effects module import'./global.css'// Side effects module import'./extend'​console.log((8).pad(3))​document.body.appendChild(Button())​Copy the code

5.1.11, SPLICT – the CHUNK

When the project becomes too large, the previous suggestion to merge all the code together becomes impractical, because it is possible that only page A needs to be previewed, while page B loads simultaneously because it is packaged together.

In practice, this waste of resources needs to be avoided, so Webpack also introduces split-chunk

Common chunks can be extracted through optimization.splitchunks

const { CleanWebpackPlugin } = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')​module.exports = {  mode: 'none', entry: {// Object configuration multi-entry file index:'./src/index.js',    album: './src/album.js'}, output: {// By way of placeholder, throw multiple exit filename:'[name].bundle.js'}, optimization: {splitChunks: {// Automatically extract all common modules into separate bundle chunks:'all'    }  },  module: {    rules: [      {        test: /\.css$/,        use: [          'style-loader'.'css-loader'        ]      }    ]  },  plugins: [    new CleanWebpackPlugin(),    new HtmlWebpackPlugin({      title: 'Multi Entry',      template: './src/index.html',      filename: 'index.html',      chunks: ['index'}), new HtmlWebpackPlugin({title:'Multi Entry',      template: './src/album.html',      filename: 'album.html',      chunks: ['album'] // Simultaneously through the corresponding reference of the chunks configuration page})]}Copy the code

5.1.12. HASHCHUNK/ Dynamic import

const {CleanWebpackPlugin} = require('clean-webpack-plugin')const HtmlWebpackPlugin = require('html-webpack-plugin')const MiniCssExtractPlugin = require('mini-css-extract-plugin')const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')const TerserWebpackPlugin = require('terser-webpack-plugin')module.exports = {    mode: 'none',    entry: {        main: './src/index.js'    },    output: {        filename: '[name]-[contenthash:8].bundle.js'}, // Optimization: {minimizer: [// If CSS compression is configured separately in this mode, then js compression needs to be configured at the same time, because if this is enabled, WebPack will think that customization is required. So you also need to configure the js compressed new TerserWebpackPlugin (), new OptimizeCssAssetsWebpackPlugin ()]}, the module: {rules: [{test: /\.css$/,                use: [                    // 'style-loader', / / the style by style tags into MiniCssExtractPlugin. Loader,'css-loader'                ]            }        ]    },    plugins: [        new CleanWebpackPlugin(),        new HtmlWebpackPlugin({            title: 'Dynamic import',            template: './src/index.html',            filename: 'index.html'}), // CSS modularize new MiniCssExtractPlugin({// Generate 8 bits when the file content changeshash            filename: '[name]-[contenthash:8].bundle.css'}})]Copy the code

index.js

// import posts from './posts/posts'// import album from './album/album'Const render = () => {const render = () => {const render = () => {const render = () => {consthash = window.location.hash || '#posts'​  const mainElement = document.querySelector('.main')​  mainElement.innerHTML = ' 'if (hash= = ='#posts'(mainelement.appendChild (posts())) {// mainelement.appendChild (posts())) // With dynamic import, webPack automatically subloads and dynamically imports. /* webpackChunkName:'components'Import (/* webpackChunkName: webpackChunkName: webpackChunkName:'components'* /'./posts/posts').then(({ default: posts }) => {      mainElement.appendChild(posts())    })  } else if (hash= = ='#album') {    // mainElement.appendChild(album())    import(/* webpackChunkName: 'components'* /'./album/album').then(({ default: album }) => {      mainElement.appendChild(album())    })    console.log(31231)  }}​render()​window.addEventListener('hashchange', render)​Copy the code

5.1.13 Implement a WEBPACK configuration for a VUE scaffolding application

webpack.common

const webpack = require('webpack')var HtmlWebpackPlugin = require('html-webpack-plugin'// Import HTML template module const StylelintPlugin = require('stylelint-webpack-plugin'); Const VueLoaderPlugin = require(VueLoaderPlugin)'vue-loader/lib/plugin')​module.exports = {    entry: './src/main.js'// The entry needs to be relative path optimization: {// Turn on sidEffects and mark it in package.json // sideEffects:true, splitChunks: {// Automatically extract all common modules into individual bundle chunks:'all'}, // the module only exports used members usedExports:true, // Whenever possible, combine each module into a function concatenateModules:true// Compress the output to minimize:true    },    module: {        rules: [            {                test: /\.vue$/,                loader: 'vue-loader'Options: {transformAssetUrls: {// Escape inline labels video: ['src'.'poster'].source: 'src',                        img: 'src',                        image: ['xlink:href'.'href'],                        use: ['xlink:href'.'href'}}}, {test: /\.js$/, exclude: /node_modules/, // node_modules package dependencies do not need to be converted, but are still included. use: { loader:'babel-loader',                    options: {                        presets: ['@babel/preset-env'}}}, {test: / \. Js |. Vue $/, exclude: / node_modules /, / / node_modules package depends on do not need to transform, but still will be packaged, similarly include is the need to include when processing. use: { loader:'eslint-loader'                },                enforce: 'pre'// Need to check before js escape}, {test: /\.(png|jpg|gif)$/i,                use: {                    loader: 'url-loader'// Load resources in data-URL mode, suitable for small static resources options: {limit: 10 x 1024, // If the value exceeds 10 KB, use file-loader. Note that file-loader must be installed. esModule:false}}}, {test: /\.css$/, // convert to js code: ['style-loader',                    {                        loader: 'css-loader',                        options: {                            sourceMap: true}}]}, {test: /\.less$/,                use: [                    'style-loader',                    {                        loader: 'css-loader',                        options: {                            sourceMap: true                        }                    },                    {                        loader: 'less-loader',                        options: {                            lessOptions: {                                strictMath: true                            },                            sourceMap: true// You can also turn on CSS sourcemap. }}]}, plugins: [new HtmlWebpackPlugin({title:'the wc' s work ',            filename: 'index.html',            template: './public/index.html',            inject: 'body'// All javascript resources are placed at the bottom of the body element}), new VueLoaderPlugin(), new webpack.DefinePlugin({ // BASE_URL:path.join(process.cwd(),'public/\/')            BASE_URL: JSON.stringify('/')// Provide a global variable when packing}), new StylelintPlugin({files: ['src/*.{vue,html,css,less}']]}})Copy the code

dev

const common = require('./webpack.common')const merge = require('webpack-merge')const path = require('path')const webpack = require('webpack')​module.exports = merge(common, {    mode: 'development',    devtool: 'cheap-module-eval-source-map',    devServer: {        contentBase: [path.join(__dirname, 'public'), path.join(__dirname, 'assets')], // The development environment does not copy static files to provide a base file to establish the correct import compress:true// All services are enabled with gzip port: 9000, // all services are enabled with gzip port: 9000, // except for common port 8080. hot:true, // hmr        open: true/ / directly open the browser}, plugins: [new webpack. HotModuleReplacementPlugin () / / on webpack own start hot drawing plugin]})Copy the code

prod

const common = require('./webpack.common')const CopyPlugin = require('copy-webpack-plugin')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const MiniCssExtractPlugin = require('mini-css-extract-plugin')const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')const TerserWebpackPlugin = require('terser-webpack-plugin')const merge = require('webpack-merge')const path = require('path')const ImageminPlugin = require('imagemin-webpack-plugin').default​module.exports = merge(common, {    mode: 'production', output: {// open eight bitshash        filename: '[name]-[contenthash:8].bundle.js',        path: path.join(__dirname, 'dist'}, optimization: {minimizer: [// If CSS compression is configured separately in this mode, then js compression needs to be configured at the same time, because if this is enabled, WebPack will think that customization is required. So you also need to configure the js compressed new TerserWebpackPlugin (), new OptimizeCssAssetsWebpackPlugin ()]}, the module: {rules: [{test: /\.less$/,                use: [                    MiniCssExtractPlugin.loader,                    'css-loader'.'less-loader'                ]            }        ]    },    devtool: 'none'Plugins: [new CleanWebpackPlugin(), // Different from development mode, static files need to be copied directly in production. New CopyPlugin({patterns: ['public'.'src/assets'}), // CSS modularize new MiniCssExtractPlugin({// Generate 8 bits when the file content changeshash            filename: '[name]-[contenthash:8].bundle.css'}), // Compress image new ImageminPlugin({pngquant: {quality:'40-50'// Compression ratio directly affects image quality. }})]})Copy the code

package.json

{  "name": "vue-app-base"."version": "0.1.0 from"."private": true."scripts": {    "serve": "webpack-dev-server --mode=development --config webpack.dev.js "."build": "webpack --mode=production --config webpack.prod.js"."eslintFix": "eslint --ext .js,.html,.vue src --fix"."lint": "webpack --config webpack.common.js"  },  "dependencies": {    "core-js": "^ 3.6.5." "."vue": "^ 2.6.11." "."webpack": "^ 4.43.0"  },  "devDependencies": {    "@babel/core": "^ 7.10.3"."@babel/preset-env": "^ 7.10.3"."@modyqyw/stylelint-config-less": "~ 1.0.0"."@vue/cli-plugin-babel": "^ 4.4.6." "."babel-loader": "^ 8.1.0"."clean-webpack-plugin": "^ 3.0.0"."copy-webpack-plugin": "^ 6.0.2." "."css-loader": "^ 3.6.0"."eslint": "^ 7.3.1"."eslint-config-standard": "^ 14.1.1." "."eslint-loader": "^ 4.0.2." "."eslint-plugin-import": "^ 2.21.2"."eslint-plugin-node": "^ 11.1.0"."eslint-plugin-promise": "^ 2"."eslint-plugin-standard": "^ 4.0.1." "."eslint-plugin-vue": "^ 6.2.2." "."file-loader": "^ 6.0.0"."html-webpack-plugin": "^ 4.3.0"."image-webpack-loader": "^ 6.0.0"."imagemin-webpack-plugin": "^" 2.4.2."less-loader": "^ 6.1.2." "."mini-css-extract-plugin": "^ 0.9.0"."optimize-css-assets-webpack-plugin": "^ 5.0.3." "."style-loader": "^ 1.2.1." "."stylelint": "^ 13.6.1." "."stylelint-config-standard": "^ 20.0.0"."stylelint-loader": "^ 6.2.0"."stylelint-webpack-plugin": "^ 2.1.0." "."terser-webpack-plugin": "^ 3.0.6"."url-loader": "^ 4.1.0." "."vue-loader": "^ 15.9.2"."vue-style-loader": "^ 4.1.2." "."vue-template-compiler": "^ 2.6.11." "."webpack-cli": "^" 3.3.12."webpack-dev-server": "^ 3.11.0"."webpack-merge": "^ 4.2.2." "  },  "eslintConfig": {    "root": true."env": {      "node": true    },    "extends": [      "plugin:vue/essential"."eslint:recommended"]."parserOptions": {      "parser": "babel-eslint"    },    "rules": {}},"browserslist": [    "1%" >."last 2 versions"."not dead"  ]}​Copy the code

eslintrc

Module.exports = {env: {browser:} // eslintConfig and.eslintrc.js files exist at the same time.true,        es2020: true    },    extends: [        'plugin:vue/essential'.'standard'    ],    parserOptions: {        ecmaVersion: 11,        sourceType: 'module'    },    plugins: [        'vue'    ],    rules: {        indent: ['error', 4] // Change to 4 Spaces. Habits}}Copy the code

eslintignore

dist/*! dist/index.jsCopy the code

stylelintrc

module.exports = {    extends: [        "stylelint-config-standard"        // "@modyqyw/stylelint-config-less"}}}}Copy the code

babel

module.exports = {    presets: [        '@vue/cli-plugin-babel/preset'    ]}​Copy the code
Vue-cli_ Manual Configuration of WEBPACK (Trampling record)

Vue-loader: “^16.0.0-beta.4”, version error, recommended to install 15.2.1

Vue-loader-plugin ^1.3.0 Lib plugin ^1.3.0

  • before

    // webpack.config.jsconst VueLoaderPlugin = require('vue-loader/lib/plugin') module.exports = {    // ...    plugins: [        new VueLoaderPlugin()    ]}Copy the code
  • now

    // webpack.config.jsconst VueLoaderPlugin = require('vue-loader-plugin'); module.exports = { // ... plugins: [ new VueLoaderPlugin() ]}Copy the code
Vue-loader-transformasseturls conversion rule

Resource URL conversion follows the following rules:

  • If the path is absolute (for example, /images/foo.png), it is retained as is.

  • Paths that start with a. Are treated as relative module dependencies and are resolved according to the directory structure on your local file system.

  • If the path starts with ~, the rest of the path is treated as a module dependency. This means that you can use this feature to reference a resource in a Node dependency:

    <img src="~some-npm-package/foo.png">Copy the code
  • Paths that start with @ are also considered module dependencies. This is useful if you configure an alias for @ in your Webpack configuration. All vue-CLI created projects are configured by default to point @ to/SRC.

Module. object error because esModule is used incorrectly. This is because esModule is enabled by default in file-loader

{    test: /\.(png|jpg|gif)$/i,        use: {            loader: 'file-loader'// Load resources in data-URL mode, suitable for small static resources options:{limit:10 x 1024,// If the value exceeds 10 KB, use file-loader. Note that file-loader must be installed. esModule:false}}};Copy the code

5.2, a rollup

5.2.1, introduction,

Rollup is a JavaScript module wrapper that compiles small pieces of code into large, complex pieces of code, such as libraries or applications.

Rollup uses new standardized formats for code modules that are included in the ES6 version of JavaScript, rather than previous ad-hoc solutions such as CommonJS and AMD. ES6 modules allow you to use the most useful stand-alone functions in your favorite library freely and seamlessly, without having to carry around other unused code in your projects. ES6 modules will eventually be implemented natively in the browser, but the current Rollup gives you an early taste.

5.2.2 zero configuration use

NPM install --dev rollup rollup main.js --file bundle.js --format iife//main.js is packaged as an entry file in the form of an iife immediately executed function and output to bundle.jsCopy the code

5.2.3 Using a configuration file

Create a file called rollup.config.js in your project and add the following code:

// rollup.config.jsexport default {  input: 'src/main.js',  output: {    file: 'bundle.js',    format: 'cjs'  }};Copy the code

5.2.4. Use PLUGIN

Install rollup-plugin-json as a development dependency:

npm install --save-dev rollup-plugin-jsonCopy the code

(We use –save-dev instead of –save, because the code doesn’t rely on the plug-in for actual execution — just for packaging.)

Update the SRC /main.js file to read data from package.json instead of SRC /foo.js:

// src/main.jsimport { version } from '.. /package.json';​export default function () {  console.log('version '+ version); }Copy the code

Edit the rollup.config.js file and add the JSON plugin:

// rollup.config.jsimport json from 'rollup-plugin-json';​export default {  input: 'src/main.js',  output: {    file: 'bundle.js',    format: 'cjs'  },  plugins: [ json() ]};Copy the code

5.2.5 Introduce the NPM module

RollUp can only import modules from local relative paths by default, and cannot directly use NPM modules like WebPack

A similar experience can be achieved with the plug-in rollUp

import json from 'rollup-plugin-json'import resolve from 'rollup-plugin-node-resolve'export default {  input: 'src/index.js',  output: {    file: 'dist/bundle.js',    format: 'iife'  },  plugins: [    json(),    resolve()  ]}​Copy the code

5.2.6 Package modules that use COMMONJS

Because rollup is recommended for esM, the CommonJS module is not supported by Rollup itself, but the CommonJS specification may be used in many third-party libraries and modules, so

Normal packaging is also available via the rollup-plugin-commonJS plug-in

import json from 'rollup-plugin-json'import resolve from 'rollup-plugin-node-resolve'import commonjs from 'rollup-plugin-commonjs'export default {  input: 'src/index.js',  output: {    file: 'dist/bundle.js',    format: 'iife'  },  plugins: [    json(),    resolve(),    commonjs()  ]}​Copy the code

5.2.7 Dynamic import and module segmentation

Just use dynamic imports in the file, and rollup automatically performs split-chunk. Note that since the code is split, it cannot be consolidated in the form of iIFE. Because it needs to run in the browser side, so select AMD specifications

export default {  input: 'src/index.js',  output: {    // file: 'dist/bundle.js',    // format: 'iife'    dir: 'dist',    format: 'amd'  }}​Copy the code

5.2.8 Multi-entry packing

export default {  // input: ['src/index.js'.'src/album.js'],  input: {    foo: 'src/index.js',    bar: 'src/album.js'  },  output: {    dir: 'dist',    format: 'amd'  }}Copy the code

index.html

<! DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">  <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title></head><body> <! -- AMD standard format output bundles cannot be directly referenced --> <! -- <script src="foo.js"></script> --> <! -- requires a library like require.js --> <script SRC ="https://unpkg.com/[email protected]/require.js" data-main="foo.js"></script></body></html>​Copy the code

5.3, parceljs

🚀 Speed packing

Parcel uses the worker process to enable multicore compilation. It also has a file system cache, allowing fast recompilation even after a restart build.

📦 Package all your resources

Parcel has out-of-the-box support for JS, CSS, HTML, files and more, and requires no plug-ins.

🐠 automatic conversion

Babel, PostCSS, and PostHTML and even node_modules packages can be used to automatically convert code if needed.

✂️ Zero configuration code split

Using the dynamic import() syntax, Parcel breaks up your output bundles so you only need to load the code you need at first load.

Hot Module Replacement

Parcel requires no configuration and automatically updates modules in the browser as your code changes while you’re developing your environment.

🚨 friendly error log

When you encounter an error, Parcel outputs syntax-highlighted snippets of code to help you locate the problem

Parceljs.org/transforms….

Understand just..

6. Code normalization

6.1, eslint

6.1.1, introduction,

  • The most popular JavaScript Lint tools monitor THE quality of JS code

  • ESLint makes it easy to unify developer coding styles

  • ESLint can help developers improve their coding capabilities

6.1.2, use,

NPM I eslint-dnpx eslint --init // Initialize ESLint to configure NPX eslint-index.jsCopy the code

6.1.3 Description of Common Configurations

module.exports = {  env: {    browser: true, // Running environment ES2020:true// extends: ['standard'ParserOptions: {ecmaVersion: 11, // esMA specificationsourceType: 'module' //sourceType has two values, script and module. Use import/for ES6+ syntaxexport}, rules: {'no-console': "warn"// custom rules}, globals: {"jQuery":"readonly"// Global variables, best not to use, will remove}}Copy the code

6.1.4 Application in GULP tool

The installation

yarn add eslint gulp-eslint -Dyarn eslint --initCopy the code

gulpfile.js

const script = () => {  return src('src/assets/scripts/*.js', { base: 'src'}). Pipe (plugins. Eslint ()), pipe (plugins. Eslint. Format ()) / / on the command line throw an error. The pipe (plugins. Eslint. FailAfterError ()) / / terminate the line .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))    .pipe(dest('temp'))    .pipe(bs.reload({ stream: true}}))Copy the code

6.1.5 WEBPACK application (REACT Project)

yarn add eslint-loader eslint  eslint-config-standard -Dyarn eslint --initCopy the code

eslintrc.js

module.exports = {  env: {    browser: true,    es2020: true  },  extends: [    'standard'.'plugin:react/recommended'// React syntax specification], parserOptions: {ecmaVersion: 11}, rules: {//'react/jsx-uses-react': / / 2'react/jsx-uses-vars': 2  }  // plugins: [  //   'react'/ /]}Copy the code

webpack.config.js

module: {    rules: [      {        test: /\.js$/,         exclude: /node_modules/,         use: 'babel-loader'      },      {        test: /\.js$/,         exclude: /node_modules/,         use: 'eslint-loader',        enforce: 'pre'}},Copy the code

6.1.6 Application in TS project

The installation

yarn add eslint -Dyarn eslint --initCopy the code

eslintrc.js

module.exports = {  env: {    browser: true,    es2020: true  },  extends: [    'standard'  ],  parser: '@typescript-eslint/parser',  parserOptions: {    ecmaVersion: 11  },  plugins: [    '@typescript-eslint'  ],  rules: {  }}​Copy the code

6.2, stylelint

6.2.1, introduction,

Check CSS/SASS /less/ postCSS syntax tools

6.2.2, use,

Yarn add stylelint-dyarn add stylelint-config-sass-guidelines -d // SCSS specification YARN add stylelint-config-standard-dCopy the code

Create stylelintrc. Js

module.exports = {  extends: [    "stylelint-config-standard"."stylelint-config-sass-guidelines"/ / sass specification]}Copy the code
yarn stylelint *.cssCopy the code

6.3, prettier

6.3.1, introduction,

Prettier is an opinionated code formatter with support for:

  • JavaScript, including ES2017

  • JSX

  • Angular

  • Vue

  • Flow

  • TypeScript

  • CSS, Less, and SCSS

  • HTML

  • JSON

  • GraphQL

  • Markdown, including GFM and MDX

  • YAML

It removes all original styling* and ensures that all outputted code conforms to a consistent style. (See this blog post)

In short, it is a code formatting tool

6.3.2, use,

yarn add prettier -Dyarn prettier index.js --write Copy the code

6.4, githooks

Git >hooks>pre-commit. Sample if we need to check the code or do anything else before committing it, we can customize it in.git>hooks>pre-commit

  • Change the file name pre-commit. Sample to pre-commit

  • Delete all comments except the first line, custom content

  • Git add. Git commit -m ‘dasdastest

The above features allow code inspection before submission

Yarn Add Husky Lint-staged -D // Husky: Write shell statements into JSON form to get Husky done more thingsCopy the code

package.json

"scripts": {    "test": "eslint ./index.js"."precommit": "lint-staged"}, / * * * * * * /"husky": {    "hooks": {      "pre-commit": "npm run precommit"}},"lint-staged": {    "*.js": [      "eslint"."git add"]}Copy the code

Complete ESLint checking before code is submitted.

Note for project release:

When publishing modules, be aware that the name in packge.json cannot be humped. The best name is XX-XX-xx.

conclusion

There may be a lot of mistakes in the article, if there is a mistake, please forgive and correct (/* manual dog head save life */), I will timely modify, I hope to grow with you.

Growth path of chicken (FLOW, TS, functional programming)

The Growing Road of Small Vegetable Chicken (ES, JS)

Growth Path of Vegetable Chicken (Function Performance Optimization)

The next chapter, vUE underlying source code analysis.