9102: Handwritten React Scaffold [Optimized Extreme Edition]

  css, html, javascript, node.js, webpack

webpackIt’s about to be 5. Handwriting an optimized scaffold is an indispensable skill.

  • The writing time of this article9 May 2019,webpackVersion4.30.0The latest version
  • All my codes are written by hand and have been tested by myself to achieve the optimization effect.
  • Welcome to my column"Advanced Front End"In the future, it will be high-quality articles from Jango.
  • If you want to reprint it, you must contact me for approval before you can reprint it. Thank you!
  • Stop5 minutesThe technology, we first in-depth principle and then write configuration, it will be much simpler.

I this code, in the development environment performance is not perfect, but build speed packaging production environment code isin seven-league bootsYes, please be sure to visit megitThe warehouse has now been added.Project practice, also in it, can give a.starOh

Implementation requirements:

    • RecognitionJSXFile
    • tree shakingShake tree optimization to remove useless code
    • Recognitionasync / awaitAnd arrow functions
    • PWAFunction, hot refresh, take over the browser immediately after installation, still allow websites to be accessed and add websites to the desktop on the mobile phone.
    • preloadPreload resourcesprefetchRequest resources on demand
    • CSSModular, not afraid of naming conflicts
    • Small picturebase64To deal with
    • File Suffix Savedjsx js jsonWait
    • Realize React lazy loading, on-demand loading, code division and support server-side rendering
    • Supportless sass stylusEqual pretreatment
    • code splitingOptimize the loading time of the first screen to prevent a file from being too large.
    • joindns-prefetchAndpreloadPre-request necessary resources to speed up the rendering of the first screen.
    • joinprerender, greatly speed up the first screen rendering speed.
    • Extract common codes and package them into onechunk
    • Each ..chunkThere is a correspondingchunkhashEach file has a correspondingcontenthashTo make it easier for browsers to distinguish between caches
    • Picture compression
    • CSSCompression
    • IncreaseCSSPrefix compatible with various browsers
    • Under the specified folder for packaging and outputting various files
    • CachebabelTo speed up the compilation speed
    • One for each entry filechunkAfter packaging, the corresponding file is alsocode spliting
    • DeleteHTMLComments on documents and other useless content
    • Delete the old packaged code for each compilation.
    • willCSSThe files are extracted separately.
    • Babel not only caches the compilation results, but also starts multi-thread compilation after the first compilation, which greatly accelerates the construction speed.
    • Wait ….
    • webpackThe slogan of the Chinese official website is: make everything simple



    In essence,webpackIs a modernJavaScriptStatic module packager for applications (module bundler)。 WhenwebpackWhen processing an application, it recursively constructs a dependency graph (dependency graph), which contains each module required by the application, and then packages all these modules into one or morebundle.

    webpack v4.0.0At first, it is not necessary to introduce a configuration file. However, the webpack is still highly configurable. Before you begin, you need to understand four core concepts:

    • Entrance (entry)
    • Output (output)
    • loader
    • Plug-ins (plugins)

    This article aims to give a high-level overview of these concepts and provide detailed related use cases of specific concepts.

    Let’s review the basics togetherWebpackKnowledge, if you are a master, please ignore these directly and look down. ….

    • Entrance

      • The entry point indicates which module the webpack should use as the starting point to build its internal dependency graph. After entering the entry p oint, the webpack will find out which modules and libraries are dependent on the entry point (directly and indirectly).
      • Each dependency is then processed and finally output to what is calledbundlesWe will discuss this process in detail in the next chapter.
      • This can be done bywebpackConfiguration in configurationentryProperty to specify an entry start point (or multiple entry start points). The default value is./src.
      • Next, let’s look at oneentryThe simplest example of configuration:

         module.exports = {
         entry: './path/to/my/entry/file.js'
      • The entry can be an object or a pure array

        entry: {
        app: ['./src/index.js', './src/index.html'],
        vendor: ['react']
        entry: ['./src/index.js', './src/index.html'],
      • Some people may say, how to put the entranceHTMLFile, because the hot update in development mode if you don’t set the entry toHTML, then changedHTMLThe contents of the file will not refresh the page and need to be refreshed manually, so here is the entry.HTMLFile, a detail.
    • Export

      • The output property tells webpack where to output the bundles it creates and how to name these files. The default value is. /dist. Basically, the entire application structure will be compiled into the folder of the output path you specify. You can configure these processes by specifying an output field in the configuration:
    const path = require('path');
    module.exports = {
    entry: './path/to/my/entry/file.js',
    output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'

    In the above example, we passedoutput.filenameAndoutput.pathProperty to tellwebpack bundleThe name of, and we want tobundleGenerate (emitWhere to. Perhaps you want to know what the path module imported at the top of the code is, it is aNode.jsThe core module is used for operating the file path.

    • loader

      • Loader enables webpack to handle non-JavaScript files (webpack itself only understands JavaScript) . Loader can convert all types of files into valid modules that can be processed by the webpack, and then you can use the packaging capability of the webpack to process them.
      • In essence, webpack loader converts all types of files into modules that can be directly referenced by the application’s dependency graph (and the final bundle).
      • Note that loader can import any type of module (e.g. css file), which is a unique feature of webpack and may not be supported by other packagers or task executors. We think this kind of language extension is neces sary because it can enable developers to create more accurate dependency graphs.
      • At a higher level, loader has two goals in the configuration of the webpack:
      • The test attribute is used to identify one or some files that should be converted by the corresponding loader.
      • The use property indicates which loader should be used when converting.

        const path = require('path');
        const config = {
        output: {
        filename: 'my-first-webpack.bundle.js'
        module: {
        rules: [
        { test: /\.txt$/, use: 'raw-loader' }
        module.exports = config;
      • In the above configuration, for a singlemoduleThe object defines the rules attribute, which contains two required attributes: test and use. This tells the webpack compiler (compiler) The following information:
      • “hey,webpackCompiler, when you encounter “inrequire()/importStatement is resolved to'.txt'Before you pack it, useraw-loaderChange it. “
      • It is important to remember that inwebpackDefined in configurationloaderWhen, to define inmodule.rules, not rules. However, when the definition is wrongwebpackSerious warnings will be given. In order to benefit from this, if you don’t do it in the right way,webpackWill “give a serious warning”
      • loaderThere are more specific configuration attributes that we haven’t mentioned yet.
      • Here, I quote the author’s excellent article and write one by hand.loaderAndplugin Handwriting a loader and plugin

    The climax is coming,webpackWhy should we learn the principle of learning first? Because at least you need to know what you write!

    • webpackPacking principle

      • Identify entry file
      • Module dependencies are identified layer by layer. (Commonjs、amdOr es6import,webpackWill analyze it. To obtain code dependencies)
      • webpackWhat you do is analyze the code. Convert code, compile code, output code
      • Finally, the packaged code is formed.
      • These are all.webpackSome basic knowledge of, for understandingwebpackThe working mechanism of is very helpful.
    • what isloader?

      • loaderIs a file loader, which can load resource files, and process these files, such as compilation, compression, and so on, and finally pack them together into a specified file.
      • Processing a file can use multipleloader,loaderThe order of execution of the is opposite to that of itself, that is, the last oneloaderFirst execution, firstloaderFinally.
      • First to be executedloaderReceive source file contents as parameters, otherloaderReceiving the previous executionloaderThe return value of is taken as a parameter. Last implementedloaderWill return to this moduleJavaScriptSource code
      • In the use of multipleloaderWhen processing files, if you want to modifyoutputPathOutput directory, please at the topOptions settings in loader
    • what isplugin?

      • InWebpackMany events will be broadcast during the life cycle of the operation.PluginYou can listen to these events and change the output results through the API provided by the Webpack at an appropriate time.
      • Plugin and loaderWhat is the difference?
      • Forloader, it is a converter that compiles a file to form a b file. here, the operation is a file, such as converting A.scss or A.less to B.css, a simple file conversion process
      • pluginIs an extender, it is richwepackIn itself, the target isloaderAfter that,webpackIn the whole packaging process, it does not directly operate the file, but works based on the event mechanism and listenswebpackSome nodes in the packaging process perform a wide range of tasks.
    • webpackOperation of

      • webpackAfter startup, the configuration will be read first.new MyPlugin(options)Initialize a MyPlugin to get its instance. After initializing the compiler object, callmyPlugin.apply(compiler)Incoming to plug-in instancecompilerObject. Plug-in instance getscompilerObject, you can pass thecompiler.plugin(Event Name, Callback Function) ListenedWebpackA broadcast event. And can pass throughcompilerObject to operatewebpack
      • See here may askcompilerWhat is it?compilationWhat is it again?
      • CompilerObject contains all the configuration information of the Webpack environment, includingoptions,loaders,pluginsThis information, this object is instantiated when the Webpack starts, it is globally unique and can be simply understood asWebpackExamples;
      • CompilationObjects contain current module resources, compiled and generated resources, changed files, etc. WhenWebpackWhen running in development mode, whenever a file change is detected, a newCompilationWill be created.CompilationObject also provides many event callbacks for plug-ins to extend. viaCompilationCan also be readCompilerObject.
      • CompilerAndCompilationThe difference lies in:
      • CompilerOn behalf of the wholeWebpackLife cycle from startup to shutdown, whileCompilationIt just represents a new compilation.
    • Event flow

      • webpackviaTapableTo organize this complex production line.
      • webpackThe event flow mechanism of ensures the order of plug-ins and makes the whole system extensible.
      • webpackThe event flow mechanism of applies observer mode, andEventEmitter in Node.jsVery similar.

    The configuration of the development environment is officially started as follows:

    • Entry settings:

      • Setting APP, several entry files, will eventually be divided into severalchunk
      • Configure in portalvendor, cancode splitingAnd finally extract these common reuse codes into onechunk, packed separately
      • In the development modeHMTLThe documents are also hot updated and need to be added.index.htmlFor import files
    entry: {
     app: ['./src/index.js', './src/index.html'],
     Vendor: ['react'] // Public codes such as redux react-redux better-scroll can also be added here
    • outputExport

      • webpackBased onNode.jsEnvironment operation, can useNode.jsTheAPI,pathmodularresolveMethod
      • For outputJSDocuments, joiningcontenthashMark, let the browser cache files, different versions.
    output: {
     filename: '[name].[contenthash:8].js',
     path: resolve(__dirname, '../dist')
    • mode: 'development'The mode selection is directly set as the development mode here, starting with the development mode.
    • resolveParse the configuration to save all file suffixesjs jsx json, add configuration

      resolve: {
      extensions: [".js", ".json", ".jsx"]
    • Add plug-in hot updatespluginAndhtml-webpack-plugin

      const HtmlWebpackPlugin = require('html-webpack-plugin')
      const webpack = require('webpack')
      new HtmlWebpackPlugin({
      template: './src/index.html'
      new webpack.HotModuleReplacementPlugin(),
    • Adding code division, the development mode also requires code division and performance optimization.
    optimization: {
     runtimeChunk: true,
     splitChunks: {
     chunks: 'all'
    • joinbabel-loaderAnd analysisJSX ES6syntacticbabel preset

      • @babel/preset-reactanalysisJsx syntax
      • @babel/preset-envanalysises6Grammar
      • @babel/plugin-syntax-dynamic-importanalysisreact-loadableTheimportLoad on demand withcode splitingFunction
      • ["import", { libraryName: "antd-mobile", style: true }],Antd-mobile on-demand loading
    loader: 'babel-loader',
    Options: {//jsx syntax
    presets: ["@babel/preset-react",
    //tree shaking loads babel-polifill on demand
    ["@babel/preset-env", { "modules": false, "useBuiltIns": "false", "corejs": 2 }]],
    plugins: [
    //Support import Lazy Loading
    //andt-mobile Loading on Demand true is less, and' css' can be written if the value of less style is not used.
    ["import", { libraryName: "antd-mobile", style: true }],
    //Identify class Components
    ["@babel/plugin-proposal-class-properties", { "loose": true }],
    cacheDirectory: true
    • jointhread-loaderInbabelTurn on multithreading after first compilation.
    const os = require('os')
    loader: 'thread-loader',
    options: {
    workers: os.cpus().length
    • ReactOn-demand loading of, with code partitioning, each on-demand loaded component will be separately partitioned into a file after packaging.
    import React from 'react'
     import loadable from 'react-loadable'
     import Loading from '../loading'
     const LoadableComponent = loadable({
     loader: () => import('../Test/index.jsx'),
     loading: Loading,
     class Assets extends React.Component {
     render() {
     return (
     < div > this will load < /div > on demand
     <LoadableComponent />
     export default Assets
    • joinhtml-loaderRecognitionhtmlFile
     test: /\.(html)$/,
     loader: 'html-loader'
    • joineslint-loader
    • The development mode end code is in the followinggitIn the warehouse

    What must be understoodwebpackPrinciple of thermal renewal:


    • webpackThe thermal update of is also called thermal replacement (Hot Module Replacement), abbreviated asHMR. This mechanism can replace the old module with the newly changed module without refreshing the browser.

    • First of all, we should know that both the server side and the client side have done the processing work.

      • The first step, inWatch for webpackIn mode, a file in the file system is modified.webpackListening to file changes, recompiling and packaging the module according to the configuration file, and passing the packaged code through a simpleJavaScriptObject is stored in memory.
      • The second step iswebpack-dev-serverAndwebpackInterface interaction between, and in this step, mainly isdev-serverMiddleware ofWebpack-dev-middleware and webpackThe interaction between them,webpack-dev-middlewarecallwebpackThe exposed API monitors code changes and tellswebpackTo package the code into memory.
      • The third step iswebpack-dev-serverA monitoring of file changes, this step is different from the first step, not monitoring code changes repackaging. When we configure thedevServer.watchContentBaseWhen true, the Server will monitor the changes of static files in these configuration folders and notify the browser to live reload the application. Note that browser refresh and HMR are two concepts here.
      • The fourth step is alsowebpack-dev-serverCode work, this step is mainly through sockjs(webpack-dev-server dependency) to establish a websocket long connection between the browser and the server, informing the browser of the status information of each stage of webpack compilation and packaging, and also including the information of the server monitoring static file changes in the third step. The browser performs different operations according to these socket messages. Of course, the most important information transmitted by the server is the hash value of the new module, and the following steps perform module thermal replacement according to this hash value.
      • webpack-dev-server/clientThe client cannot request updated code or perform hotswap module operations, and returns these tasks to thewebpack,webpack/hot/dev-serverOur work is based onwebpack-dev-server/clientInformation sent to it anddev-serverThe configuration of the determines whether to refresh the browser or to perform a module hot update. Of course, if only refreshing the browser, there would be no subsequent steps.
      • HotModuleReplacement.runtimeIt is the hub of the client HMR and receives the new module passed to it in the previous step.hashValue, which passes through theJsonpMainTemplate.runtimeSends an Ajax request to the server, and the server returns onejson, whichjsonContains hash values of all modules to be updated. After obtaining the update list, the module obtains the latest module code through jsonp request again. This is the steps 7, 8 and 9 in the above figure.
      • And step 10 is the key step to determine the success of HMR. In this step,HotModulePluginThe new and old modules will be compared to decide whether to update the modules. After deciding to update the modules, the dependency relationship between the modules will be checked and the dependency references between the modules will be updated while updating the modules.
      • The last step, whenHMRAfter failure, retreat backlive reloadOperation, that is, to refresh the browser to obtain the latest packaged code.
      • Reference articleWebpack face exam-tengxuyun

    The official start of the production process:

    • joinWorkboxPlugin,PWAPlug-in for

      • pwaIn fact, if this technology is to be used well, it still needs some efforts. It has its life cycle and the side effects brought about by hot updates in browsers, etc., which need careful study. You can refer to Baidu’slavasHistory of Framework Development ~
    const WorkboxPlugin = require('workbox-webpack-plugin')
    new WorkboxPlugin.GenerateSW({
    Clients claim: true//let the browser be taken over immediately.
    Skipwaiting: true//jump the queue to the front immediately after updating the sw file.
    importWorkboxFrom: 'local',
    include: [/\.js$/, /\.css$/, /\.html$/,/\.jpg/,/\.jpeg/,/\.svg/,/\.webp/,/\.png/],
    • Add a plug-in that empties the last package file with each package output file.
    const CleanWebpackPlugin = require('clean-webpack-plugin')
     new CleanWebpackPlugin()
    • joincode splitingCode division
    optimization: {
    RuntimeChunk:true, // set to true, a chunk is a file after it is packaged, and a chunk corresponds to' some js css pictures', etc.
    splitChunks: {
    Chunks: 'all' // the default entry's chunk will not be split. if it is configured as all, it will be split. an entry' JS',
    //After packaging, a separate file will be generated.
    • Add separate extractionCSSdocumentaryloaderAnd plug-ins
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
     test: /\.(less)$/,
     use: [
     loader: 'css-loader', options: {
     modules: true,
     localIdentName: '[local]--[hash:base64:5]'
     { loader: 'less-loader' }
     new MiniCssExtractPlugin({
    • Add compressioncssPlug-in for
    const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
    new OptimizeCssAssetsWebpackPlugin({
    preset:['default',{discardComments: {removeAll:true} }]
    • killhtmlSome useless code
    new HtmlWebpackPlugin({
    template: './src/index.html',
    minify: {
    removeComments: true,
    collapseWhitespace: true,
    removeRedundantAttributes: true,
    useShortDoctype: true,
    removeEmptyAttributes: true,
    removeStyleLinkTypeAttributes: true,
    keepClosingSlash: true,
    minifyJS: true,
    minifyCSS: true,
    minifyURLs: true,
    • Add picture compression
    test: /\.(jpg|jpeg|bmp|svg|png|webp|gif)$/,
    {loader: 'url-loader',
    options: {
    limit: 8 * 1024,
    name: '[name].[hash:8].[ext]',
    loader: 'img-loader',
    options: {
    plugins: [
    interlaced: false
    progressive: true,
    arithmetic: false
    floyd: 0.5,
    speed: 2
    plugins: [
    { removeTitle: true },
    { convertPathData: false }
    • joinfile-loaderPack and export some files to a fixed directory.
     exclude: /\.(js|json|less|css|jsx)$/,
     loader: 'file-loader',
     options: {
     outputPath: 'media/',
     name: '[name].[contenthash:8].[ext]'

    There are some comments that may not be detailed. The code is written bit by bit by myself. If you have tried, it will definitely not be any problem.

    • Dependency required
    "name": "webpack",
    "version": "1.0.0",
    "main": "index.js",
    "license": "MIT",
    "dependencies": {
    "@babel/core": "^7.4.4",
    "@babel/preset-env": "^7.4.4",
    "@babel/preset-react": "^7.0.0",
    "autoprefixer": "^9.5.1",
    "babel-loader": "^8.0.5",
    "clean-webpack-plugin": "^2.0.2",
    "css-loader": "^2.1.1",
    "eslint": "^5.16.0",
    "eslint-loader": "^2.1.2",
    "file-loader": "^3.0.1",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "imagemin": "^6.1.0",
    "imagemin-gifsicle": "^6.0.1",
    "imagemin-mozjpeg": "^8.0.0",
    "imagemin-pngquant": "^7.0.0",
    "imagemin-svgo": "^7.0.0",
    "img-loader": "^3.0.1",
    "less": "^3.9.0",
    "less-loader": "^5.0.0",
    "mini-css-extract-plugin": "^0.6.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "postcss-loader": "^3.0.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-loadable": "^5.5.0",
    "react-redux": "^7.0.3",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "webpack": "^4.30.0",
    "webpack-cli": "^3.3.2",
    "webpack-dev-server": "^3.3.1",
    "workbox-webpack-plugin": "^4.3.1"
    "scripts": {
    "start": "webpack-dev-server --config ./config/webpack.dev.js",
    "dev": "webpack-dev-server --config ./config/webpack.dev.js",
    "build": "webpack  --config  ./config/webpack.prod.js "
    "devDependencies": {
    "@babel/plugin-syntax-dynamic-import": "^7.2.0"

    The whole project andwebpackThe configured source code address has been updated:Source code address, can you see it, dear

    The little fellow passing by would like to give a compliment to star. It’s so hard to write! ! ! !