Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Analysis of web front-end modularization

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly introduces "analyzing web front-end modularization". In daily operation, I believe many people have doubts in analyzing web front-end modularization. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful for you to answer the doubts about "analyzing web front-end modularization". Next, please follow the editor to study!

Background

It is well known that early JavaScript natives did not support modularity until 2015, when TC39 released ES6, and one of the specifications was ES modules (for ease of expression, later referred to as ESM). But before the ES6 specification was proposed, there were already some modularization schemes, such as CommonJS (in Node.js) and AMD. What ESM has in common with these specifications is that both import and export syntax are supported, except that there are some differences in the keywords of their behavior.

CommonJS

/ / add.js const add = (a, b) = > a + b module.exports = add / / index.js const add = require ('. / add') add (1,5)

AMD

/ / add.js define (function () {const add = (a, b) = > a + b return add}) / / index.js require (['. / add'], function (add) {add (1,5)})

ESM

/ / add.js const add = (a, b) = > a + b export default add / / index.js import add from'. / add' add (1,5)

The background to the emergence of JavaScript modularity has been introduced in the previous chapter ("previous lives of Front-end Modularization"), and I will not repeat it here. However, the emergence of ESM is different from other specifications, because it is a modular scheme officially launched by JavaScript. Compared with CommonJS and AMD schemes, ESM uses a completely static way to load modules.

ESM specification

Module export

Module exports have only one keyword: export, and the easiest way is to add the export keyword directly before the declared variable.

Export const name = 'Shenfq'

You can add export directly before const, let, var, or export directly before function or class.

Export function getName () {return name} export class Logger {log (... args) {console.log (... args)}}

The above export method can also be abbreviated using curly braces.

Const name = 'Shenfq' function getName () {return name} class Logger {log (... args) {console.log (... args)}} export {name, getName, Logger}

The last syntax, which we often use, exports the default module.

Const name = 'Shenfq' export default name

Module import

The module is imported using import, with the from keyword.

/ / main.js import name from'. / module.js' / / module.js const name = 'Shenfq' export default name

In this way of direct import, export default, that is, import syntax, must be used in module.js, and the default module is imported by default. If you want to import other modules, you must use the syntax of object expansion.

/ / main.js import {name, getName} from'. / module.js' / / module.js export const name = 'Shenfq' export const getName = () = > name

If the module file exports both the default module and other modules, you can import both at the same time.

/ / main.js import name, {getName} from'. / module.js' / / module.js const name = 'Shenfq' export const getName = () = > name export default name

Of course, ESM also provides renaming syntax to rename imported modules.

/ / main.js import * as mod from'. / module.js' let name =''name = mod.name name = mod.getName () / / module.js export const name =' Shenfq' export const getName = () = > name

The above writing is equivalent to re-assigning the object exported by the module:

/ / main.js import {name, getName} from'. / module.js' const mod = {name, getName}

Individual variables can also be renamed:

/ / main.js import {name, getName as getModName}

Import and export simultaneously

If there are two modules an and b, and module c is introduced at the same time, but these two modules also need to import module d, if modules an and b import d after importing c, it is also possible to import d, but it is a bit tedious. We can directly import module d into module c and expose module d.

/ / module_c.js import {name, getName} from'. / module_d.js' export {name, getName}

It still seems a bit troublesome to write this way, and here ESM provides a syntax that combines import and export.

Export {name, getName} from'. / module_d.js'

The above are some of the basic syntax of the ESM specification. If you want to know more, you can read teacher Ruan's introduction to ES6.

The difference between ESM and CommonJS

First of all, there must be grammatical differences, which have been briefly introduced earlier, one using import/export syntax and the other using require/module syntax.

Another significant difference between ESM and CommonJS is that the variables of the ESM import module are strongly bound. Once the variables of the export module change, the variables of the corresponding import module will also change, while the imported modules in CommonJS are value transfer and reference transfer, similar to function parameters (basic types pass values, which is equivalent to copying variables, non-basic types [objects, arrays], reference passing).

Let's take a look at the detailed examples:

CommonJS

/ / a.js const mod = require ('. / b') setTimeout (() = > {console.log (mod)}, 1000) / / b.js let mod = 'first value' setTimeout (() = > {mod =' second value'}, 500) modmodule.exports = mod$ node a.js first value

ESM

/ / a.mjs import {mod} from'. / b.mjs' setTimeout (() = > {console.log (mod)}, 1000) / / b.mjs export let mod = 'first value' setTimeout (() = > {mod =' second value'}, 500) $node-- experimental-modules a.mjs # (node:99615) ExperimentalWarning: The ESM module loader is experimental. Second value

In addition, the module implementation of CommonJS actually makes a layer of function package for each module file, which makes each module get require/module and _ _ filename/__dirname variables. Take the above a.js as an example. The a.js running code in the actual execution process is as follows:

/ / a.js (function (exports, require, module, _ _ filename, _ _ dirname) {const mod = require ('. / b') setTimeout (() = > {console.log (mod)}, 1000)})

The ESM module is implemented through the import/export keyword, and there is no corresponding function package, so in the ESM module, you need to use the import.meta variable to get _ _ filename/__dirname. Import.meta is a specific object implemented by ECMAScript that contains module metadata, which is mainly used to store module url, while node only supports loading local modules, so url uses file: protocol.

Import url from 'url' import path from' path' / / import.meta: {url: file:///Users/dev/mjs/a.mjs} const _ _ filename = url.fileURLToPath (import.meta.url) const _ dirname = path.dirname (_ _ filename)

The principle of loading

Steps:

Construction (Construction): download all files and parse to module records.

Instantiation (instance): put all exported variables into memory at the specified location (but not yet). Then, let both the export and import point to the memory specified location. This is called "linking".

Evaluation (evaluation): executes the code, gets the value of the variable and places it in memory.

Module record

All modular development starts with an entry file, which is retrieved by both Node.js and browsers, and all other dependent files are found step by step.

/ / Node.js: main.mjs import Log from'. / log.mjs'

It is worth noting that at the beginning of getting the entry file, we do not know which modules it depends on, so we must first go through the static analysis of the js engine to get a module record that contains the file's dependencies. Therefore, the js file you get at first will not be executed, but will be converted to a module record (module records). All import modules are recorded in the importEntries field of the module record, and more fields related to the module record can be found in tc39.es.

Module construction

Once the module record is obtained, all dependencies are downloaded and the dependency file is converted to the module record again until there is no dependency file, a process known as construction.

Module construction consists of the following three steps:

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

Module identification (parse dependent module url to find the real download path)

File download (download from the specified url or load from the file system)

Convert to module record (module records).

The ESM specification has detailed instructions on how to convert module files into module records, but there is no corresponding description in the ESM specification on how to download these dependent module files in the construction step. Because of how to download files, there are different implementation specifications on both the server side and the client side. For example, in a browser, how to download a file belongs to the HTML specification (the browser's modules are loaded with tags).

Although downloads are not part of ESM's existing specification at all, there is also a url address in the import statement that references the module, and there are some differences between Node and browsers about how this address needs to be translated. To put it simply, you can import modules in node_modules directly in Node, but not directly in browsers, because browsers cannot correctly find out where the node_modules directory on the server is. Fortunately, there is a proposal called import-maps, which is mainly used to solve the problem that browsers cannot import module identifiers directly. However, until the proposal is fully implemented, url can only be used for module import in browsers.

{"imports": {"jQuery": "/ node_modules/jquery/dist/jquery.js"}} import $from 'jQuery' $(function () {$(' # app') .html ('init')})

Downloaded modules will be converted into module records and then cached in module map. If you encounter the same dependency on different files, they will be directly obtained in the module map cache.

/ / log.js const log = console.log export default log / / file.js export {readFileSync as read, writeFileSync as write} from 'fs'

Module instance

Once all the dependent files are obtained and the module map is established, all module records are found and all exported variables are fetched, and then all variables are mapped into memory one by one, and the corresponding relationships are stored in the Module Environment record (module environment record). Of course, the current variable in memory has no value, just initializes the corresponding relationship. After initializing the correspondence between export variables and memory, the correspondence between module imports and memory is set immediately to ensure that the imports and exports of the same variables point to the same memory area, and that all imports can find the corresponding exports.

Module connection

Because the import and export point to the same memory area, once the export value changes, the import value also changes, and all values that are different from CommonJS,CommonJS are copy-based. After connecting to the import and export variables, we need to put the corresponding values into memory, and then we will proceed to the evaluation step.

Module evaluation

The evaluation step is relatively simple, as long as you run the code to fill in the previously recorded memory address. At this point, you can happily use ESM modularization.

The Progress of ESM

Because ESM appears late, the server already has a CommonJS solution, and the client has a webpack packaging tool, so the promotion of ESM has to be said to be very difficult.

Client

Let's first take a look at the support of the client. It is recommended that you check it directly in Can I Use. The following is a screenshot of 2019 Universe 11.

So far, major browsers have already supported ESM, just pass in the specified type= "module" in the script tag.

In addition, we know that in Node.js, the .mjs suffix is sometimes needed to use ESM, but browsers don't care about file suffixes, as long as the MIME type of the http response header is correct (Content-Type: text/javascript). Also, when type= "module", defer is enabled by default to load the script. Here is an additional picture of difference between defer and async.

We know that when browsers do not support script, noscript tags are provided for degraded processing, and modularity provides similar tags.

Alert ('current browser does not support ESM!')

This allows us to load files directly using a modular scheme for browsers that support ESM, and webpack-packaged versions for browsers that are not supported.

Preload

We know that the browser's link tag can be used as a preload for resources, for example, I need to preload the main.js file:

If the main.js file is a modular file, it doesn't make sense for the browser to preload a single file. As we said earlier, a modular file needs to be downloaded to get module records, module instances and module evaluation, so we have to find a way to tell the browser that this file is a modular file, so the browser provides a new rel type. Designed for preloading modular files.

Current situation

Although major browsers already support ESM, according to chrome, only 1% of pages are used. The screenshot time is 2019 Universe 11.

Server side

Browsers can specify whether the current script is handled as a module through the script tag, but there is no clear way to indicate whether or not to use ESM in Node.js, and there is already a standard modularization scheme for CommonJS in Node.js. Even if ESM is enabled, how to determine whether the module imported by the current portal file uses ESM or CommonJS? In order to solve the above problems, the node community began to appear the relevant draft of ESM, which can be found on github.

Node.js 8.5.0, released in 2017, enables experimental support for ESM. When starting the program, add-experimental-modules to enable support for ESM, and parse files with the .mjs suffix as ESM. The early expectation was that Node.js 12 would be officially released in LTS state, and then it didn't happen until the recent 13.2.0 release officially supported ESM, that is, canceling the experimental-modules startup parameter. Details can be found in the official documentation of Node.js 13.2.0.

There are two completely different attitudes about the .mjs suffix community. The proponents believe that distinguishing types by file suffixes is the simplest and most explicit way, and there have already been similar cases in the community, such as. Jsx for React components and. Ts for ts files The supporters believe that .js has existed as a js suffix for so many years, it is visually difficult to accept a .mjs is also a js file, and many existing tools are .js suffix to identify js files, if the introduction of a .mjs program, there are a large number of tools need to be modified to effectively adapt to ESM.

So in addition to specifying the ESM with the .mjs suffix, you can also use the type attribute of the pkg.json file. If the type attribute is module, it means that the current module should use ESM to resolve the module, otherwise CommonJS should be used to resolve the module.

{"type": "module" / / module | commonjs (default)}

Of course, some local files don't have pkg.json, but you don't want to use the .mjs suffix, so you just need to add a startup parameter-- input-type=module-- to the command line. Input-type also supports the commonjs parameter to specify the use of CommonJS (--input-type=commonjs).

To summarize, in Node.js, the module loading mode of ESM is enabled in the following three situations:

The file suffix is .mjs

The type field in pkg.json is specified as module

Add the startup parameter-- input-type=module.

Similarly, there are three situations in which CommonJS's module loading is enabled:

The file suffix is .cjs

The type field in pkg.json is specified as commonjs

Add the startup parameter-- input-type=commonjs.

Although version 13.2 removes the startup parameter for experimental-modules, according to the documentation, the use of ESM in Node.js is still an experimental feature.

Stability: 1-Experimental

However, it is believed that by the time the Node.js 14 LTS version is released, ESM support should enter a stable phase, and there is also a full list of Node.js plans for ESM.

At this point, the study on "analyzing web front-end modularization" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report