In a Web project, we might use two different modules: the ES module and the CommonJS module. Using require and import to load these two modules may produce different results. If we want to write a JS library for others to use, export a different type of module, it will be used differently for the user. Let’s take a look at how WebPack translates the export and load of these two modules.
- commonjs
const myModule = 'module';
module.exports = myModule;
Copy the code
- es module
const myModule = 'module';
export default myModule;
Copy the code
Package a simple module
Suppose we wrote a module like this:
class Person {
constructor(name) {
this.name = name; }}// es module
export default Person
Copy the code
Then we use Webpack to package a UMD module for others to use. The umD module packaged by Webpack looks like this:
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports= = ='object' && typeof module= = ='object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports= = ='object')
exports["Person"] = factory();
else
root["Person"] = factory();
})(self, function(){/ *... * /})
Copy the code
As you can see, when other people use our module, they actually get the return value of the Factory function. We won’t delve into the inner details of the Factory function here, but readers who are interested can do so. We just say the conclusion:
- For the ES module, after webpack is packed, factory returns the value like this:
{
default: class Person{/ *... * /},
_esModule: true[Symbol.toStringTag]: 'Module'./ /...
}
Copy the code
- For commonJS modules, the factory return value is the exported value directly:
class Person(a){/ *... * /}
Copy the code
Module is written after we release it to the NPM, in order to support the script tags introduced, we also put js published to the CDN server, assuming that the link is https://cdn.test.com/person.js.
use
Import using the script tag
<script src="https://cdn.test.com/person.js"></script>
<script>
var sam = new Person('Sam');
</script>
Copy the code
When we open the page, we will find an error because our module is exported as export Default, so person. default is the constructor we want. A simple solution is to write modules using module.exports.
The use of NPM
In a Web project that uses a build tool, we might use the require function to load modules, for example:
const Person = require('person');
const sam = new Person('Sam');
Copy the code
Similarly, since the Person module is exported by export default, the above writing method will give an error. The correct writing method should be:
const Person = require('person').default;
const sam = new Person('Sam');
Copy the code
But if we use import syntax to load modules, we don’t have the annoying default attribute:
import Person from 'person';
const sam = new Person('Sam');
Copy the code
Why is there no default with import syntax? Remember, the require and import we wrote here will be translated by Webpack. Module loading functions that are translated using require and import are different. If we use import, the compiled code will determine if the module is es Module when it loads, and will redefine the getter function to help us get the module export value correctly.
conclusion
Through the above analysis, we can probably draw the following two conclusions:
- If you want to use WebPack to compile your code into umD modules so that it behaves consistently across different module systems, the best way to write the source code is as a CommonJS module.
- In fact, the es module is a better choice than the UMD module:
The ES module is the official standard and the clear direction of the JavaScript language, and the CommonJS module is a special traditional format that was used as a temporary solution until the ES module was proposed. The ES module allows static analysis, enabling optimizations like tree-shaking, and provides advanced features such as circular references and dynamic binding.
So for a browser-side module, it’s better to write an ES module and let the user load it using import. If our module needs to support both browser and Node environments, we can use rollup package to output two pieces of code, one commonJS module and one ES module, and then set the module and main fields of package.json to be compatible.