The principles of the webpack organization module and the webpack Module

Source: Internet
Author: User

The principles of the webpack organization module and the webpack Module

Now, the frontend uses Webpack to package JS files and other files. With the popularity of Node, the front-end engineering method and backend become more and more similar. All things are modularized and finally compiled in a unified manner. Due to the constant updates of Webpack versions and various complicated configuration options, it is often difficult to get confused when using Webpack. So it is good to know how the Webpack organizes the compilation module and how the generated code is executed. Otherwise, it will always be a black box. Of course, I am a front-end hacker. I recently started to study the principles of Webpack. Here I will make a little record.

Compilation Module

Compiling two words sounds like a black technology, and the code generated is often a huge volume of Cloud stuff, so it is often frustrating, but in fact the Core Principles inside are not difficult. The so-called Webpack compilation is, in fact, only after Webpack analyzes your source code, it makes some modifications to it, and then organizes all the source code in one file. Finally, a large bundle JS file is generated and executed by the browser or other Javascript Engines and the result is returned.

Here is a simple case to illustrate the principles of the Webpack packaging module. For example, we have a module named mA. js.

var aa = 1;function getDate() { return new Date();}module.exports = { aa: aa, getDate: getDate}

I randomly defined a variable aa and a function getDate, and then export it. Here we use CommonJS.

Then define an app. js. As the main file, it is still in the CommonJS style:

var mA = require('./mA.js');console.log('mA.aa =' + mA.aa);mA.getDate();

Now we have two modules, which are packaged using Webpack. The entry file is app. js, which depends on the module mA. js. Webpack has to do a few things:

  1. From the entry module app. js, analyze the dependencies of all modules and read all modules used.
  2. The source code of each module is organized in an immediate function.
  3. Rewrite the syntax related to require and export in the module code and their corresponding reference variables.
  4. Create a module Management System in the final bundle file to dynamically load the modules used in runtime.

Let's take a look at the result of the Webpack package in the above example. The final bundle file is generally a large function to be executed immediately. The organizational layers are complex and a large number of names are obscure. Therefore, I have made some modifications and modifications here, make it as easy as possible.

The first step is to list all modules used and create a table with their file names (generally full paths) as IDS:

var modules = { './mA.js': generated_mA, './app.js': generated_app}

What is the above generated_xxx? It is a function that wraps the source code of each module into a local scope, so as not to expose internal variables. In fact, it turns every module into an execution function. It is defined as follows:

Function generated_module (module, exports, webpack_require) {// code of the module. //...}

The specific code of the module here refers to generating code, and Webpack refers to generated code. For example, mA is rewritten to get the following result:

function generated_mA(module, exports, webpack_require) { var aa = 1;  function getDate() {  return new Date(); } module.exports = {  aa: aa,  getDate: getDate }}

At first glance, it seems to be exactly the same as the source code. Indeed, mA does not have require or import other modules, and export uses the traditional CommonJS style, so the generated code is not changed. However, it is worth noting that the last module. exports = ..., the module here is the parameter module passed in from the outside. This actually tells us that the module's mA source code will be executed when this function is run, in addition, the content that requires export will be saved to the external, which marks the completion of mA loading, and the external thing is actually the module management system to be mentioned later.

Next, let's look at the code generated by app. js:

function generated_app(module, exports, webpack_require) { var mA_imported_module = webpack_require('./mA.js');  console.log('mA.aa =' + mA_imported_module['aa']); mA_imported_module['getDate']();}

You can see that app. in the source code of js, the mA part of the introduced module is modified because neither require/exports nor ES6-style import/export can be directly executed by the JavaScript interpreter, it depends on the module Management System to embody these abstract keywords. That is to say, webpack_require is the specific implementation of require. It can dynamically load the module mA and return the result to the app.

At this point, you may have initially developed a module management system. Let's take a look at the implementation of webpack_require:

// All loaded modules. Var installedModules ={}; function webpack_require (moduleId) {// If the module has been loaded, read it directly from the Cache. If (installedModules [moduleId]) {return installedModules [moduleId]. exports;} // create a new module and add it to installedModules. Var module = installedModules [moduleId] = {id: moduleId, exports :{}}; // load the module, that is, the code generated by the running module, modules [moduleId]. call (module. exports, module, module. exports, webpack_require); return module. exports ;}

Note that the modules in the last sentence is the generated code of all modules we have previously defined:

var modules = { './mA.js': generated_mA, './app.js': generated_app}

The logic of webpack_require is clearly written. First, check whether the module has been loaded. If so, the module's exports results are directly returned from the Cache. If it is a brand new module, establish the corresponding data structure module and run the generated code of this module. This function is passed in to the module object and its exports domain, this is actually the origin of exports and modules in CommonJS. After this function is run, the module is loaded and the result of the export needs to be saved to the module object.

Therefore, we can see that the principle of the so-called module management system is actually very simple. As long as you have patiently understood them, there is no esoteric thing. It is composed of these three parts:

// Code generated for all modules var modules; // All loaded modules are used as the cache table var installedModules; // function webpack_require (moduleId) of the loaded module );

Of course, all the above Code is packaged in a large anonymous function that is executed immediately in the compiled bundle file. The final returned sentence is as follows:

return webpack_require(‘./app.js');

Load the entry module app. js. All subsequent dependencies are dynamically and recursively loaded at runtime. Of course, the Code actually generated by Webpack is slightly different, and its structure is roughly like this:

(function(modules) { var installedModules = {};  function webpack_require(moduleId) {   // ... } return webpack_require('./app.js');}) ({ './mA.js': generated_mA, './app.js': generated_app});

It can be seen that it directly uses modules as the parameter for immediate function execution, instead of being defined separately. Of course, this is essentially different from the above method, I made this rewrite to make it clearer.

ES6 import and export

The above examples are all written in the traditional CommonJS method. The more general ES6 style is now using the import and export keywords, which are also slightly different in use. However, for Webpack or other module management systems, these new features should only be regarded as syntactic sugar. They are essentially the same as require/exports, such as export:

Export aa // equivalent to module. exports ['a'] = aaexport default bb // equivalent to module. exports ['default'] = bb

For import:

Import {aa} from './mA. js' // equivalent to var aa = require ('./mA. js') ['a']

This is special:

import m from './m.js'

The situation will be a little more complicated. It needs to load the default export of module m, and module m may not be written by the export of ES6, or there may be no export default at all, therefore, when Webpack generates a generated code for the module, it will determine whether it is an ES6-style export. For example, we define the module mB. js:

let x = 3;let printX = () => { console.log('x = ' + x);}export {printX}export default x

It uses the export of ES6, so the Webpack will add a sentence in the generated code of mB:

Function generated_mB (module, exports, webpack_require) {Object. defineProperty (module. exports, '_ esModule', {value: true}); // mB code //....}

That is to say, it marks a _ esModule for the mB export, indicating that it is an ES6-style export. In this way, in other modules, when a dependency module is similar to import m from '. /m. when loading js in this way, it will first determine whether it is an ES6 export module. If yes, its default is returned. If not, the entire export object is returned. For example, the above mA is a traditional CommonJS, And the mB is ES6:

// mA is CommonJS moduleimport mA from './mA.js'console.log(mA);// mB is ES6 moduleimport mB from './mB.js'console.log(mB);

We define the get_export_default function:

function get_export_default(module) { return module && module.__esModule? module['default'] : module;}

In this way, after the generated code is run, different results will be obtained on mA and mB:

Var mA_imported_module = webpack_require ('. /mA. js '); // print the complete mA_imported_moduleconsole.log (get_export_default (mA_imported_module); var mB_imported_module = webpack_require ('. /mB. js'); // print the mB_imported_module ['default'] console. log (get_export_default (mB_imported_module ));

This is where some special processing is required for Webpack on ES6 import. However, ES6's import/export is essentially no different from CommonJS, in addition, the generated code generated by Webpack is based on the module/exports mechanism of CommonJS to load modules.

Module Management System

The preceding figure shows how to package and organize modules and interpret the loading of the runtime module. In fact, the principle of Webpack is not difficult. The core idea is to establish a module management system, this is also universal, if you have read Node. the source code of the Module part of js will find that it is actually using a similar method. Here is an article for reference.

The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.