理解cjs和esm在npm包开发中应用分析

923 阅读3分钟

前言

  • cjs就是commonJS,node里面就是这种模块化形式,不能在浏览器工作,需要通过转换打包
  • esm js的标准模块化系统方案,具有cjs的简单语法,amd的异步;常用方式import

场景应用

CJS方式和ESM方式写入文件

node执行文件的时候,识别不了esm方式的写法

node在几个场景把内容识别为ES模块

  • 带有.mjs扩展名的文件,优先级大于type配置
  • package.json的module配置为type

还有一种方式会识别成ESM模式

  • 使用标记为参数带有--eval,或者通过管道传递node vi字符串。

STDIN --input-type=module

例子中没办法识别为ES模块,应该是用法的问题

混用的时候,type是为module

Modules loaders模块加载器的加载情况

commonjs模块加载器

  • 同步
  • 负责处理require()
  • 可修补
  • 支持文件夹做模块
  • 找不到匹配时,会找.js .json等,然后会尝试把文件夹解析为模块
  • 不能加载ECMAscript模块

ECMAScript模块加载器

  • 异步
  • 负责处理 import import()
  • 不可修补,使用loader hook自定义
  • 不支持文件为模块,必须制定目录索引
  • 不进行扩展搜索
  • 可以加载json,需要断言
  • 只接受.js, .mjs cjs可扩展名
  • 可用于加载commonjs,通过cjs-module-lexer

执行问题

commonjs模式运行不了是因为使用了export,export是esm的写法,而esm模式运行不了是因为,本身getUrlParms方法没有做为到处的方式来写。

  • main字段只是定义包的主要入口点。

之前支持两种模式的方法

借助 Node 原生支持 CJS 去支持 require 语法,借助 Webpack 等打包工具去识别 package.json 的 module 字段,从而支持 ESM,相对 require 还顺便做到了 tree-shaking。

  • node14.13 后提供了exports配置可以解决一些问题,通过不同的指向在引用的时候使用不同的模块

exports使用配置不同环境下,不同的模块入口文件

例如一些第三方 UI 包需要引入对应的样式文件才能正常使用,

import `packageA/dist/css/index.css`;

"exports": { "./style": "./dist/css/index.css' },

import `packageA/style`;

例子

在用typescript结合来开发工具库的同时要了解tsconfig.json中的几个重要参数配置

moduleResolution

模块解析策略,参数 'node'[用于nodejs的commonjs实现], 'node16'[4.7开始支持nodenext], 'classic'[1.6之前]

Specify how TypeScript looks up a file from a given module specifier.

指定 TypeScript 如何从给定的模块说明符中查找文件。

paths

避免代码库中有较长的相对映射

module

指定生成什么模块代码。

target

设置更改了JS哪些功能需要被降级,那些功能保持不变,例如是ES5的,箭头是否要转换为function。【慎用ESNext】

noEmit

不去编译输出文件,如果JS源代码,源映射或说明

resolveJsonModule

允许解析'.json'扩展名的模块

files

指定程序中允许包括的文件,如果找不到任何文件,则会发生错误

includes

制定要包含的文件名或者模式数组【支持通配符来实现glob模式】

exclude

排除include设置的部分文件

allowUnreachableCode

使用 JavaScript 语法而无法访问的代码有关

noImplicitReturns

确保声明后的返回值的能够匹配

rootDirs

允许编辑器解析这些虚拟目录的相对模块导入,好像被合并到同个目录一样

不会影响TS转成JS的方式

"rootDirs": ["src", "generated"]

outFile

所有全局【非模块的】文件连接输出到指定的单个文件

allowSyntheticDefaultImports

允许编写导入

import React from "react"; 替代 import * as React from "react"

esModuleInterop

esModule模块的一些操作,默认情况下,TS会把commonjs/amd/umd

模块视为ES6模块,但是会出现的影响

import * as moment from "moment"

const moment = require("moment")

出现default问题,找不到该default,像Ts,babel, webpack都有相应的机制去处理,这里这个配置就是开启Ts对这块的处理。

import moment from "moment"

const moment = require("moment").default

参考链接

code.zuifengyun.com/2022/08/252…

www.kancloud.cn/chandler/we…

juejin.cn/post/714500…

nodejs.org/api/package…

zhuanlan.zhihu.com/p/148081795