Record – Implementation wraps Webpack

Function introduction:

  1. The optimized WebPack configuration is ready to use out of the box with a single package installation, and does not have to deal with the version dependencies and upgrade issues among the various dependencies within WebPack (all webPack related packages are wrapped in it).
    • (Similar to the vue-cli-service command)@vue/cli-serviceA file namedvue-cli-serviceThe command. You can do this in NPM Scriptsvue-cli-serviceOr from the terminal./node_modules/.bin/vue-cli-serviceAccess this command. Such as:
      {
        "scripts": {
          "serve": "vue-cli-service serve"."build": "vue-cli-service build"}}Copy the code
  2. In addition to the built-in optimized WebPack configuration, you can also customize the WebPack configuration by writing webpack.config.js in the same format as the official WebPack standard

Outline of this article

  1. What does wrapping webpack mean?
  2. What are the benefits of wrapping WebPack?
  3. How do I wrap webPack?
    1. Difficulty 1: A command platform is required
    2. Difficulty 2: The webpack and webpack-dev-serve commands need to be executed inside the packaged package
    3. Difficulty 3: How to pass parameters to the webpack configuration file? (Configuration file is called by Webpack, can not pass parameters normally)
    4. Difficulty 4: You need to read the user-written WebPack configuration and override the default configuration

The following will be introduced in accordance with the above outline

1. What does webpack mean?

First let’s look at what it looks like before and after encapsulation

package.json

/ / before packaging{..."devDependencies": {
    "webpack": "^ 4.9.1." "."webpack-cli": "^ 3.3.10"."webpack-dev-server": "^ 3.11.2"."babel-loader": "^ 8.2.2"."css-loader": "^ 2.1.1"."file-loader": "^ 3.0.1." "."less-loader": "^ 5.0.0"."postcss-loader": "^ 3.0.0"."sass-loader": "^ 7.1.0"."style-loader": "^ 0.23.1"."vue-loader": "^ 15.7.2"."url-loader": "^ 1.1.2." ".// There are also some webpack loader and plugin, omitted}}// Only one package needs to be loaded after encapsulation{..."devDependencies": {
     "@myCompany/fe": "^ 1.0.68",}}Copy the code

Encapsulation means, in fact, all webPack-related dependencies are encapsulated in a package, the ability to use WebPack only need to download this package. Here are the benefits

2. What are the benefits of wrapping Webpack?

Why encapsulate? What are the benefits of encapsulation?

The benefits are:

Background: Internally, there are 10+ separate projects, each with its own Webpack configuration, and many of them are close to each other. The projects are similar, and it is possible to unify webpack into a package.

This way, the optimal configuration (with various performance optimizations) can be used uniformly, and only one package version is required, and all 10+ projects can be updated to the latest configuration. Can achieve the front-end project unified high quality optimization. (See below, personalization is also supported)

And users do not have to worry about the version dependency relationship and version upgrade between various dependency packages within Webpack, I will deal with the internal unified

3. How to wrap Webpack?

  1. Difficulty 1: A command platform is required
  2. Difficulty 2: The webpack and webpack-dev-serve commands need to be executed inside the packaged package
  3. Difficulty 3: How to pass parameters to the webpack configuration file? (Configuration file is called by Webpack, can not pass parameters normally)
  4. Difficulty 4: Need to read the custom webPack configuration written by the user, and then overwrite the internal default configuration

Difficulty 1: A command platform is required

We already have the tool platform to build the internal front end tool platform. We just need to add one more configuration item in the code of the tool platform, such as FE Run. The details can be as follows

Fe run dev Similar to NPM run dev fe run Similar to NPM run buildCopy the code

Webpack-related dependencies are also placed on the tool platform, and the webpack command is then executed directly from within the package

  • There is a crucial detail here
    // package.json{..."dependencies": {... All packages on the tool platform (including Webpack and dependencies) should be placed in it, not in it"devDependencies"},},},}Copy the code

Difficulty 2: The webpack and webpack-dev-serve commands need to be executed inside the packaged package

Executing commands, such as Webpack XX, requires spawn

  • The CWD execution path must be configured in spawn. Otherwise, an error occurs
const { spawn } = require('child_process') // Run the LNPM I command

// Start subprocesses to execute commands, such as NPM install
const runCommand = (obj) = > {
  const { command, args=[], fn, cwd } = obj
  // console.log('-----', cwd)
  const runner = spawn(command, args, {
    stdio: 'inherit'.// (inherits the stdio output of the parent process) prints information about NPM install
    cwd: cwd || null // Execute environment path
  })
  runner.on('close'.function (code) {
    if(fn) {fn(code)}})} * Here is a detail: "Spawn" requires CWD to be configured. If you don't configure CWD, it will execute the command in the execution path by default. For example, the current project is QWER, and we want to package QWER, Now within the directory of QWER QWER xxxMacBook - Pro % PWD/Users/XXX/Desktop/project/QWER if CWD is not in spawn configuration, then would operate within webpack QWER directory xx. Obviously not what we want, we want to execute webpack xx in the @myCompany/fe directoryCopy the code

There is also a problem here. If you use spawn to execute webpack, an error will be reported, even if CWD is set in spawn and the @myCompany/fe directory is located.

  • The reason is the blocking nature of node_modules dependencies, so commands cannot be invoked across dependencies. Also, the user environment may have WebPack installed globally, and different versions may also affect the final results

NPM: NPM run xx: NPM run xx: NPM run xx: NPM run xx: NPM run xx

let isDev = false // Default mode: production, fe run
if (process.argv.pop() === 'dev') { // fe run dev will execute in this, mode dev
    isDev = true
}
runCommand({
    command: 'npm'.// The command to execute is NPM
    args: ['run', isDev ? 'dev' : 'build'].// NPM run dev or NPM run build
    cwd: path.resolve(__dirname, '.. /.. / ') // Execute in the tool platform path
})

// This is eventually triggered by NPM run dev or build, on the command line: you need to tell Webpack to use --config to read the default configuration file webpack.config.js
"dev": "webpack-dev-server --open --hot --env.NODE_ENV=development --progress --mode=development --config ./bin/webpackConfig/webpack.config.js"
"build": "webpack --inline --env.NODE_ENV=production --progress --mode=production --hide-modules --config ./bin/webpackConfig/webpack.config.js"
Copy the code

At this point fe Run Dev and FE Run are ready to perform webpack packing, and the configuration files are configured by default. Next, you need to configure it so that users can override the default configuration

Difficulty 3: How to pass parameters to the webpack configuration file? (Configuration file is called by Webpack, can not pass parameters normally)

Background: In the webpack configuration file, entry needs to get the path of the corresponding project, and output also needs the path. This path must be dynamic

Difficulty: The Webpack configuration file is called by Webpack, and parameters cannot be normally transmitted

Solution: Get the parameters through an intermediary: “file”. Get the parameters by reading the file

  • The user to performfe cliTo package, you can take the current execution path PWD and write this path to a local file. The webpack configuration file is webpack.config.js and you can add code to read local files (for example:const CONFIG = require('./obj.js')) to get path parameters.
    • Other parameters can be retrieved this way if needed

Difficulty 4: Need to read the custom webPack configuration written by the user, and then overwrite the internal default configuration

The core is webpack-Merge

To give an example, the user needs to write a configuration file in the root directory of the project: for example: fe.config.js

// fe.config.js
module.exports = {
  webpack: {...// You can write the webpack configuration in the same format as the standard format, and eventually merge the configuration through webpack-merge
    
    / / such as:
    entry: 'xx' 
    output: {
      path: 'xx'
    },
    plugins: []}}Copy the code

Const getFeConfig = require(‘ package fe.config.js path’)


Code word is not easy, praise encouragement!