Node.js v18.8.0 文档


目录

ECMAScript 模块#

中英对照

介绍#

中英对照

ECMAScript 模块是来打包 JavaScript 代码以供重用的官方标准格式。 模块使用各种 importexport 语句定义。



启用#

中英对照

Node.js 有两个模块系统:CommonJS 模块和 ECMAScript 模块。

#

中英对照

此章节已移至包模块

import 说明符#

术语#

中英对照

import 语句的说明符是 from 关键字之后的字符串,例如 import { sep } from 'node:path' 中的 'node:path'。 说明符也用于 export from 语句,并作为 import() 表达式的参数。

    强制的文件扩展名#

    中英对照

    当使用 import 关键字解析相对或绝对的说明符时,必须提供文件扩展名。 还必须完全指定目录索引(例如 './startup/index.js')。

    URL#

    中英对照

    ES 模块被解析并缓存为 URL。 这意味着特殊字符必须是百分比编码的,比如使用 %23#、使用 %3F?

    file: URL#

    中英对照

    如果用于解析模块的 import 说明符具有不同的查询或片段,则会多次加载模块。

    
    

    data: 导入#

    中英对照

    data: URL 支持使用以下 MIME 类型导入:

      
      

      node: 导入#

      中英对照

      支持 node: URL 作为加载 Node.js 内置模块的替代方法。 此 URL 协议允许有效的绝对的 URL 字符串引用内置模块。

      
      

      导入断言#

      中英对照

      导入断言提案为模块导入语句添加了内联语法,以便在模块说明符旁边传入更多信息。

      
      

      内置模块#

      中英对照

      核心模块提供了其公共 API 的命名导出。 还提供了默认导出,其是 CommonJS 导出的值。 默认导出可用于修改命名导出等。 内置模块的命名导出仅通过调用 module.syncBuiltinESMExports() 进行更新。

      
      
      
      
      
      

      import() 表达式#

      中英对照

      动态的 import() 在 CommonJS 和 ES 模块中都受支持。 在 CommonJS 模块中它可以用来加载 ES 模块。

      import.meta#

      中英对照

        import.meta 元属性是包含以下属性的 Object

        import.meta.url#

        中英对照

          这与提供当前模块文件 URL 的浏览器中的定义完全相同。

          
          

          import.meta.resolve(specifier[, parent])#

          中英对照

          此特性仅在启用 --experimental-import-meta-resolve 命令标志时可用。

            
            

            
            

            与 CommonJS 的互操作性#

            import 声明#

            中英对照

            import 语句可以引用 ES 模块或 CommonJS 模块。 import 语句只允许在 ES 模块中使用,但 CommonJS 支持动态 import() 表达式来加载 ES 模块。

            require#

            中英对照

            CommonJS 模块 require 总是将它引用的文件视为 CommonJS。

            CommonJS 命名空间#

            中英对照

            CommonJS 模块由可以是任何类型的 module.exports 对象组成。

            
            

            
            

            
            

            
            

            ES 模块和 CommonJS 之间的差异#

            没有 require、exports 或 module.exports#

            中英对照

            在大多数情况下,可以使用 ES 模块 import 加载 CommonJS 模块。

            没有 __filename 或 __dirname#

            中英对照

            这些 CommonJS 变量在 ES 模块中不可用。

            没有原生模块加载#

            中英对照

            ES 模块导入当前不支持原生模块。

            没有 require.resolve#

            中英对照

            相对解析可以通过 new URL('./local', import.meta.url) 处理。

            没有 NODE_PATH#

            中英对照

            NODE_PATH 不是解析 import 说明符的一部分。 如果需要这种行为,则使用符号链接。

            没有 require.extensions#

            中英对照

            require.extensions 没有被 import 使用。 期望加载器钩子在未来可以提供这个工作流。

            没有 require.cache#

            中英对照

            require.cache 没有被 import 使用,因为 ES 模块加载器有自己独立的缓存。

            JSON 模块#

            中英对照

            import 可以引用 JSON 文件:

            
            

            Wasm 模块#

            中英对照

            --experimental-wasm-modules 标志下支持导入 WebAssembly 模块,允许将任何 .wasm 文件作为普通模块导入,同时也支持它们的模块导入。

            
            

            
            

            顶层的 await#

            中英对照

            await 关键字可以用在 ECMAScript 模块的顶层主体中。

            
            

            
            
            
            

            
            

            HTTPS 和 HTTP 导入#

            中英对照

            --experimental-network-imports 标志下支持使用 https:http: 导入基于网络的模块。 这允许类似网络浏览器的导入在 Node.js 中工作,但由于应用程序稳定性和安全问题在特权环境而不是浏览器沙箱中运行时会有所不同,因此存在一些差异。

            导入仅限于 HTTP/1#

            中英对照

            尚不支持 HTTP/2 和 HTTP/3 的自动协议协商。

            HTTP 仅限于环回地址#

            中英对照

            http: 易受中间人攻击,不允许用于 IPv4 地址 127.0.0.0/8127.0.0.1127.255.255.255)和 IPv6 地址 ::1 之外的地址。 对 http: 的支持旨在用于本地开发。

            永远不会发送身份验证到目标服务器#

            中英对照

            AuthorizationCookieProxy-Authorization 标头未发送到服务器。 避免在部分导入的 URL 中包含用户信息。 正在研究在服务器上安全使用这些的安全模型。

            永远不会在目标服务器上检查 CORS#

            中英对照

            CORS 旨在允许服务器将 API 的使用者限制为一组特定的主机。 这不受支持,因为它对于基于服务器的实现没有意义。

            无法加载非网络依赖项#

            中英对照

            这些模块不能访问不超过 http:https: 的其他模块。 要在避免安全问题的同时仍然访问本地模块,则传入对本地依赖项的引用:

            
            
            
            

            默认情况下不启用基于网络的加载#

            中英对照

            目前,需要 --experimental-network-imports 标志来启用通过 http:https: 加载资源。 将来,将使用不同的机制来执行此操作。 需要选择加入以防止不经意间使用可能影响 Node.js 应用程序可靠性的潜在可变状态的传递依赖关系。

            加载器#

            中英对照

            要自定义默认的模块解析,则可以选择通过 Node.js 的 --experimental-loader ./loader-name.mjs 参数提供加载器钩子。

            
            

            钩子#

            中英对照

            钩子是链的一部分,即使该链仅由一个自定义(用户提供的)钩子和始终存在的默认钩子组成。 钩子函数嵌套:每个函数都必须返回一个普通对象,并且链接发生在每个函数调用 next<hookName>() 的结果中,next<hookName>() 是对后续加载程序钩子的引用。

            resolve(specifier, context, nextResolve)#

            中英对照

              resolve 钩子链负责解析给定模块说明符和父 URL 的文件 URL,以及可选的格式(例如 'module')作为对 load 钩子的提示。 如果指定了格式,则 load 钩子最终负责提供最终的 format 值(可以随意忽略 resolve 提供的提示);如果 resolve 提供了 format,则需要自定义 load 钩子,即使只是通过 Node.js 默认 load 钩子的值。

              
              
              load(url, context, nextLoad)#

              中英对照

                load 钩子提供了一种方式来定义确定网址应如何解释、检索、以及解析的自定义方法。 它还负责验证导入断言。

                  
                  

                  globalPreload()#

                  中英对照

                    有时可能需要在应用程序运行所在的同一全局范围内运行一些代码。 此钩子允许返回在启动时作为宽松模式脚本运行的字符串。

                    
                    

                    
                    

                    示例#

                    中英对照

                    各种加载器钩子可以一起使用来完成对 Node.js 代码加载和评估行为的广泛定制。

                    HTTPS 加载器#

                    中英对照

                    在当前的 Node.js 中,以 https:// 开头的说明符是实验性的(参见 HTTPS 和 HTTP 导入)。

                    
                    
                    
                    

                    转译器加载器#

                    中英对照

                    可以使用 load 钩子将 Node.js 无法理解的格式的源代码转换为 JavaScript。 但是,在调用该钩子之前,resolve 钩子需要告诉 Node.js 不要在未知文件类型上抛出错误。

                    
                    
                    
                    
                    
                    

                    解析算法#

                    特性#

                    中英对照

                    解析器具有以下属性:

                      解析器算法#

                      中英对照

                      加载 ES 模块说明符的算法通过下面的 ESM_RESOLVE 方法给出。 它返回相对于 parentURL 的模块说明符的解析 URL。

                        解析器算法规范#

                        ESM_RESOLVE(specifier, parentURL)

                        1. Let resolved be undefined.
                        2. If specifier is a valid URL, then
                          1. Set resolved to the result of parsing and reserializing specifier as a URL.
                        3. Otherwise, if specifier starts with "/", "./", or "../", then
                          1. Set resolved to the URL resolution of specifier relative to parentURL.
                        4. Otherwise, if specifier starts with "#", then
                          1. Set resolved to the result of PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, defaultConditions).
                        5. Otherwise,
                          1. Note: specifier is now a bare specifier.
                          2. Set resolved the result of PACKAGE_RESOLVE(specifier, parentURL).
                        6. Let format be undefined.
                        7. If resolved is a "file:" URL, then
                          1. If resolved contains any percent encodings of "/" or "\" ("%2F" and "%5C" respectively), then
                            1. Throw an Invalid Module Specifier error.
                          2. If the file at resolved is a directory, then
                            1. Throw an Unsupported Directory Import error.
                          3. If the file at resolved does not exist, then
                            1. Throw a Module Not Found error.
                          4. Set resolved to the real path of resolved, maintaining the same URL querystring and fragment components.
                          5. Set format to the result of ESM_FILE_FORMAT(resolved).
                        8. Otherwise,
                          1. Set format the module format of the content type associated with the URL resolved.
                        9. Load resolved as module format, format.

                        PACKAGE_RESOLVE(packageSpecifier, parentURL)

                        1. Let packageName be undefined.
                        2. If packageSpecifier is an empty string, then
                          1. Throw an Invalid Module Specifier error.
                        3. If packageSpecifier is a Node.js builtin module name, then
                          1. Return the string "node:" concatenated with packageSpecifier.
                        4. If packageSpecifier does not start with "@", then
                          1. Set packageName to the substring of packageSpecifier until the first "/" separator or the end of the string.
                        5. Otherwise,
                          1. If packageSpecifier does not contain a "/" separator, then
                            1. Throw an Invalid Module Specifier error.
                          2. Set packageName to the substring of packageSpecifier until the second "/" separator or the end of the string.
                        6. If packageName starts with "." or contains "\" or "%", then
                          1. Throw an Invalid Module Specifier error.
                        7. Let packageSubpath be "." concatenated with the substring of packageSpecifier from the position at the length of packageName.
                        8. If packageSubpath ends in "/", then
                          1. Throw an Invalid Module Specifier error.
                        9. Let selfUrl be the result of PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL).
                        10. If selfUrl is not undefined, return selfUrl.
                        11. While parentURL is not the file system root,
                          1. Let packageURL be the URL resolution of "node_modules/" concatenated with packageSpecifier, relative to parentURL.
                          2. Set parentURL to the parent folder URL of parentURL.
                          3. If the folder at packageURL does not exist, then
                            1. Continue the next loop iteration.
                          4. Let pjson be the result of READ_PACKAGE_JSON(packageURL).
                          5. If pjson is not null and pjson.exports is not null or undefined, then
                            1. Return the result of PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions).
                          6. Otherwise, if packageSubpath is equal to ".", then
                            1. If pjson.main is a string, then
                              1. Return the URL resolution of main in packageURL.
                          7. Otherwise,
                            1. Return the URL resolution of packageSubpath in packageURL.
                        12. Throw a Module Not Found error.

                        PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL)

                        1. Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(parentURL).
                        2. If packageURL is null, then
                          1. Return undefined.
                        3. Let pjson be the result of READ_PACKAGE_JSON(packageURL).
                        4. If pjson is null or if pjson.exports is null or undefined, then
                          1. Return undefined.
                        5. If pjson.name is equal to packageName, then
                          1. Return the result of PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions).
                        6. Otherwise, return undefined.

                        PACKAGE_EXPORTS_RESOLVE(packageURL, subpath, exports, conditions)

                        1. If exports is an Object with both a key starting with "." and a key not starting with ".", throw an Invalid Package Configuration error.
                        2. If subpath is equal to ".", then
                          1. Let mainExport be undefined.
                          2. If exports is a String or Array, or an Object containing no keys starting with ".", then
                            1. Set mainExport to exports.
                          3. Otherwise if exports is an Object containing a "." property, then
                            1. Set mainExport to exports["."].
                          4. If mainExport is not undefined, then
                            1. Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, mainExport, "", false, false, conditions).
                            2. If resolved is not null or undefined, return resolved.
                        3. Otherwise, if exports is an Object and all keys of exports start with ".", then
                          1. Let matchKey be the string "./" concatenated with subpath.
                          2. Let resolved be the result of PACKAGE_IMPORTS_EXPORTS_RESOLVE( matchKey, exports, packageURL, false, conditions).
                          3. If resolved is not null or undefined, return resolved.
                        4. Throw a Package Path Not Exported error.

                        PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, conditions)

                        1. Assert: specifier begins with "#".
                        2. If specifier is exactly equal to "#" or starts with "#/", then
                          1. Throw an Invalid Module Specifier error.
                        3. Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(parentURL).
                        4. If packageURL is not null, then
                          1. Let pjson be the result of READ_PACKAGE_JSON(packageURL).
                          2. If pjson.imports is a non-null Object, then
                            1. Let resolved be the result of PACKAGE_IMPORTS_EXPORTS_RESOLVE( specifier, pjson.imports, packageURL, true, conditions).
                            2. If resolved is not null or undefined, return resolved.
                        5. Throw a Package Import Not Defined error.

                        PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey, matchObj, packageURL, isImports, conditions)

                        1. If matchKey is a key of matchObj and does not contain "*", then
                          1. Let target be the value of matchObj[matchKey].
                          2. Return the result of PACKAGE_TARGET_RESOLVE(packageURL, target, "", false, isImports, conditions).
                        2. Let expansionKeys be the list of keys of matchObj containing only a single "*", sorted by the sorting function PATTERN_KEY_COMPARE which orders in descending order of specificity.
                        3. For each key expansionKey in expansionKeys, do
                          1. Let patternBase be the substring of expansionKey up to but excluding the first "*" character.
                          2. If matchKey starts with but is not equal to patternBase, then
                            1. Let patternTrailer be the substring of expansionKey from the index after the first "*" character.
                            2. If patternTrailer has zero length, or if matchKey ends with patternTrailer and the length of matchKey is greater than or equal to the length of expansionKey, then
                              1. Let target be the value of matchObj[expansionKey].
                              2. Let subpath be the substring of matchKey starting at the index of the length of patternBase up to the length of matchKey minus the length of patternTrailer.
                              3. Return the result of PACKAGE_TARGET_RESOLVE(packageURL, target, subpath, true, isImports, conditions).
                        4. Return null.

                        PATTERN_KEY_COMPARE(keyA, keyB)

                        1. Assert: keyA ends with "/" or contains only a single "*".
                        2. Assert: keyB ends with "/" or contains only a single "*".
                        3. Let baseLengthA be the index of "*" in keyA plus one, if keyA contains "*", or the length of keyA otherwise.
                        4. Let baseLengthB be the index of "*" in keyB plus one, if keyB contains "*", or the length of keyB otherwise.
                        5. If baseLengthA is greater than baseLengthB, return -1.
                        6. If baseLengthB is greater than baseLengthA, return 1.
                        7. If keyA does not contain "*", return 1.
                        8. If keyB does not contain "*", return -1.
                        9. If the length of keyA is greater than the length of keyB, return -1.
                        10. If the length of keyB is greater than the length of keyA, return 1.
                        11. Return 0.

                        PACKAGE_TARGET_RESOLVE(packageURL, target, subpath, pattern, internal, conditions)

                        1. If target is a String, then
                          1. If pattern is false, subpath has non-zero length and target does not end with "/", throw an Invalid Module Specifier error.
                          2. If target does not start with "./", then
                            1. If internal is true and target does not start with "../" or "/" and is not a valid URL, then
                              1. If pattern is true, then
                                1. Return PACKAGE_RESOLVE(target with every instance of "*" replaced by subpath, packageURL + "/").
                              2. Return PACKAGE_RESOLVE(target + subpath, packageURL + "/").
                            2. Otherwise, throw an Invalid Package Target error.
                          3. If target split on "/" or "\" contains any ".", "..", or "node_modules" segments after the first segment, case insensitive and including percent encoded variants, throw an Invalid Package Target error.
                          4. Let resolvedTarget be the URL resolution of the concatenation of packageURL and target.
                          5. Assert: resolvedTarget is contained in packageURL.
                          6. If subpath split on "/" or "\" contains any ".", "..", or "node_modules" segments, case insensitive and including percent encoded variants, throw an Invalid Module Specifier error.
                          7. If pattern is true, then
                            1. Return the URL resolution of resolvedTarget with every instance of "*" replaced with subpath.
                          8. Otherwise,
                            1. Return the URL resolution of the concatenation of subpath and resolvedTarget.
                        2. Otherwise, if target is a non-null Object, then
                          1. If exports contains any index property keys, as defined in ECMA-262 6.1.7 Array Index, throw an Invalid Package Configuration error.
                          2. For each property p of target, in object insertion order as,
                            1. If p equals "default" or conditions contains an entry for p, then
                              1. Let targetValue be the value of the p property in target.
                              2. Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, targetValue, subpath, pattern, internal, conditions).
                              3. If resolved is equal to undefined, continue the loop.
                              4. Return resolved.
                          3. Return undefined.
                        3. Otherwise, if target is an Array, then
                          1. If _target.length is zero, return null.
                          2. For each item targetValue in target, do
                            1. Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, targetValue, subpath, pattern, internal, conditions), continuing the loop on any Invalid Package Target error.
                            2. If resolved is undefined, continue the loop.
                            3. Return resolved.
                          3. Return or throw the last fallback resolution null return or error.
                        4. Otherwise, if target is null, return null.
                        5. Otherwise throw an Invalid Package Target error.

                        ESM_FILE_FORMAT(url)

                        1. Assert: url corresponds to an existing file.
                        2. If url ends in ".mjs", then
                          1. Return "module".
                        3. If url ends in ".cjs", then
                          1. Return "commonjs".
                        4. If url ends in ".json", then
                          1. Return "json".
                        5. Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(url).
                        6. Let pjson be the result of READ_PACKAGE_JSON(packageURL).
                        7. If pjson?.type exists and is "module", then
                          1. If url ends in ".js", then
                            1. Return "module".
                          2. Throw an Unsupported File Extension error.
                        8. Otherwise,
                          1. Throw an Unsupported File Extension error.

                        LOOKUP_PACKAGE_SCOPE(url)

                        1. Let scopeURL be url.
                        2. While scopeURL is not the file system root,
                          1. Set scopeURL to the parent URL of scopeURL.
                          2. If scopeURL ends in a "node_modules" path segment, return null.
                          3. Let pjsonURL be the resolution of "package.json" within scopeURL.
                          4. if the file at pjsonURL exists, then
                            1. Return scopeURL.
                        3. Return null.

                        READ_PACKAGE_JSON(packageURL)

                        1. Let pjsonURL be the resolution of "package.json" within packageURL.
                        2. If the file at pjsonURL does not exist, then
                          1. Return null.
                        3. If the file at packageURL does not parse as valid JSON, then
                          1. Throw an Invalid Package Configuration error.
                        4. Return the parsed JSON source of the file at pjsonURL.

                        自定义的 ESM 说明符解析算法#

                        中英对照

                        当前的说明符解析不支持 CommonJS 加载器的所有默认行为。 行为差异之一是文件扩展名的自动解析以及导入具有索引文件的目录的能力。

                        
                        
                        返回顶部