now the front end packaging of JS and other files with Webpack is the mainstream, coupled with the popularity of Node, making the front end of the engineering and back end more and more like. All things are modular, and finally unified compilation. Webpack because of the continuous update of the version and the various complex configuration options, some of the mistakes in the use are often inconvenient. So it's good to know how Webpack organizes the compilation module and how the generated code is executed, otherwise it will always be a black box. Of course, I'm a front-end white, and recently I just started to study the principle of Webpack and do a little record here.

compiler compiler module two word sounds very black technology, plus the generated code is often a large pile of incomprehensible things, so often daunting, but in fact, the core principle is not what difficult inside. The compilation of Webpack is only Webpack after analyzing your source code, making some modifications to it, and then organizing all source code into a single file. Finally, a large bundle JS file is generated, which is executed by the browser or other Javascript engines and returns the result. Here

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

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

I can define a variable AA and a function of getDate, then export, here is the use of CommonJS method.

then define a app.js as a main file, is still CommonJS

 var style: 

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

); now we have two modules, using Webpack package, entrance file is app.js, depending on the mA.js module Webpack, to do several things:

  1. starting from the entrance module app.js, analyzing the dependency relationship of all modules, the use of all modules are read in. The source code for each module of
  2. is organized in a function that is immediately executed. The
  3. rewriting module code neutralizes the syntax related to require and export, as well as their corresponding reference variables.
  4. sets up a module management system in the last generated bundle file that can dynamically load the modules used in runtime.

we can look at the example above, the results that Webpack has packaged. The final bundle file is generally a large immediate execution function. The organization level is rather complex, and the large number of naming is also obscure. So I did some rewriting and modification here, making it as simple and easy as possible.

is the first of all the modules are listed, with their file name (usually the full path) is ID, the establishment of a table:

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

is the key to the above generated_xxx is what? It is a function that encapsulate the source code of each module, making it a local scope, so that it doesn't expose internal variables, and actually turn each module into an executive function. It is defined in general is this:

 function generated_module (module, exports, webpack_require) {/ / module specific code. 

} / /... Here module specific code refers to the code generation, Webpack called generated code. For example mA, adapted to get such a result:

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

at first glance seems as like as two peas and source code. Indeed, mA has no require or other import modules, and export uses a traditional CommonJS style, so there is no change in generating code. But it is worth noting that the final module.exports =..., parameter module where module is coming from the outside, this is in fact told us that the operation of this function, mA module source code will be executed, and finally to the contents of the export will be saved to the outside, here marks the mA loaded, and the external things are actually behind said module management system.

then look at the generated code:

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'] (

);} can be seen on the introduction of the app.js module mA source code in the part of the changes, because whether it is require/exports or ES6 style import/export, can be directly executed the JavaScript interpreter, it needs to rely on the system management module, these abstract specific keywords. That is to say, webpack_require is the concrete implementation of require, which can dynamically load the module mA and return the result to the app.

here is your mind may have initially gradually construct a module management system idea, we look at the implementation of webpack_require: all modules loaded

 / / 

. Var installedModules = {}; function webpack_require (moduleId) {/ / if the module has been loaded, read directly from the Cache. If (installedModules[moduleId] return) {installedModules[moduleId].exports}; / / create a new module and added to the installedModules. Var module = installedModules[moduleId] = id: {exports:} moduleId {}; / / loading module, running code generation module, modules[moduleId].call (module.exports, module, module.exports, webpack_require); return module.exports;}

note second last sentence modules is before we defined all the modules of the generated code:

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

webpack_require} logic written very clearly, first check module is already loaded, if it is directly from the Cache module of the exports results returned. If the new module, then establish the corresponding data structure of module, and run the module of generated code, this function is built into the module object, and its exports domain, which is actually the origin of exports and module in CommonJS. When the function is finished, the module is loaded and the result of the export is saved to the module object.

so we see the so-called modular management system, the principle is very simple, as long as the patient will they tease out what no esoteric things, which is composed of three parts:

 / / all modules of code generation var modules; / / all already loaded module, as the cache table var installedModules; / / load module function function webpack_require (moduleId); 

of all the above code in the compiled bundle file, wrapped in a large, immediate implementation of the anonymous function, finally return is such a sentence:

 return webpack_require ("./app.js') 

is loaded; entrance module app.js, behind all the dependence will dynamically and recursively loaded in runtime. Of course, the real Webpack generated code is slightly different in structure, it 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}); 

can see it is directly modules as a parameter is passed into the immediate execution of the function definition rather than the other, and of course the above wording not what essentially different from me to do so is to rewrite the explanation more clearly. The examples of

ES6's import and export

above are all written by traditional CommonJS. Now the more general ES6 style is using import and export keywords, but also slightly different in usage. But for Webpack or other module management system, these new features should only be considered as syntactic sugar, they essentially like require/exports, such as export:

 export AA is equivalent to module.exports['aa'] = AA: / / BB / / export default is equivalent to BB 

: module.exports['default'] =

import:

 import {aa} from for'./mA.js'/ / equivalent var AA = require ('./mA.js') ['aa'] 

special is this:

 import m from'./m.js'

will be a little more complicated, it need to load the module of M default export, and M may not be a module by ES6 export to write, may also have no export default, so Webpack when generating generated code modules, ES6 will determine whether it is not the wind The grid of the export, such as mB.js:

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

, it uses ES6 export, then Webpack mB generated in code will add a sentence:

 function generated_mB (module, exports, webpack_require) {Object.defineProperty (module.exports,'__esModule', {value:, true}); / / specific code / / mB...} 

. That is to say, it gives the mB export marked a __esModule, that it is the style of ES6 export. So in other modules, when a dependent module is loaded in a way similar to import m from'./m.js', it will first decide if a module is generated by ES6 export. If it is, return its default, if not, return the entire export object. For example, the above mA is the traditional CommonJS, mB is ES6 style:

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

we define get_export_default function:

 function get_export_default (module) {return module & & module.__esModule; module; 

? Module['default']:

generated code} after operation in mA and mB will get different results:

 var mA_imported_module = webpack_require ('./mA.js'); / / print complete mA_imported_module (get_export_default console.log (mA_imported_module)); VAR mB_imported_module = webpack_require ('./mB.js'); / / print mB_imported_module['default'] (console.log get_export_default (mB_im Ported_module)); 

, which is where Webpack needs to do some special processing on the import of the ES6. But in general, ES6's import/export is essentially different from CommonJS, and Webpack's last generated generated code is also based on CommonJS module/exports mechanism to achieve module loading. The

module management system

is how Webpack packages the organization


This concludes the body part