node.js系列-多种方案教你在node程序中同时使用CommonJS 和 ES Module 混合开发最佳实践

前情提要

我们平时使用的npm 第三方包一般基于这两种规范开发的,很容易遇到一个项目里既有 CommonJS 又有 ES Module 的情况,那么我们应该如何解决这种CommonJS 和 ES Module 混合开发的问题呢?

CommonJS是什么?

  • 2009年,美国程序员Ryan Dahl创造了node.js项目,将javascript语言用于服务器端编程。这标志"Javascript模块化编程"正式诞生。在服务器端,需要有模块,与操作系统和其他应用程序互动。
  • CommonJS 是为了提供一个类似Python,Ruby和Java标准库,让开发者可以使用CommonJS API编写应用程序,可以运行在不同的JavaScript解释器和不同的主机环境中。
  • NodeJS,webpack 我们通常会以CommonJS的形式来书写。
CommonJS可以开发以下程序:

(1)、服务器端JavaScript应用程序
(2)、命令行工具
(3)、图形界面应用程序
(4)、混合应用程序(如,Titanium或Adobe AIR)

代码形式

通俗大白话,特点就是: 使用require关键词来引入依赖,举个例子:

const path = require('path')
const AutoLoad = require('@fastify/autoload')

以及 module.exports

module.exports = async function (fastify, opts) {
  fastify.get('/', async function (request, reply) {
    return 'this is an example'
  })
}

ES module是什么?

ES Modules(ESM)是用于处理模块的 ECMAScript 标准。 虽然 Node.js 长期使用 CommonJS 标准,但浏览器从未有过模块系统。 每个主要决策(如模块系统)必须首先由 ECMAScript 标准化,然后由浏览器实施。

ES modules(ESM) 是 JavaScript 官方的标准化模块系统。

ES 模块是如何运作的

当使用模块来开发的时候,会建立一个模块模块依赖图。不同依赖之间联系来自于你使用的任何 import 语句。

区别

  • CommonJS 按需加载,可以动态加载、条件加载、循环加载
  • ESM 静态加载,方便解析依赖,优化运行效率。 import() 目前也可以动态加载
  • CommonJS 模块输出值的拷贝,ESM输出值的引用。
  • CommonJS 运行时加载,ESM编译时输出接口。
  • CommonJS 模块的require()同步加载,ESM的import异步加载,有独立模块依赖解析阶段。
  • ESM的import会提升,变量const只读。
区别举例

在CommonJS中我们可以直接使用__dirname,就像下面这样:

fastify.register(AutoLoad, {
    dir: path.join(__dirname, 'plugins'),
    options: Object.assign({}, opts)
  })

但是在ESM中不再支持,我们需要改为

import {dirname} from 'path';
import { fileURLToPath } from 'url';

function getDirname(url) {
  const __filename = fileURLToPath(url);
  return dirname(__filename);
}

解决方案

方案1:按照 ES Module 规范,指定 “type”

单独指定某些文件使用 CommonJS 模块,或者ES Module 模块

  • 正常情况下,我们不做配置的话,项目默认是 CommonJS 规范
  • 在 package.json 文件中指定 “type”:“module” 后,就会按照 ES Module 规范
  • 强制的指定文件后缀为 .cjs后,此文件会遵守CommonJS 规范


ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and 'test/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
ReferenceError: 在 ES 模块范围中没有定义要求,您可以使用 import 代替
这个文件被视为 ES 模块,因为它有一个’。Js 的文件扩展名和‘ test/package.json’包含“ type”: “ module”。若要将其视为 CommonJS 脚本,请将其重命名为使用’。Cjs 的文件扩展名。
“type”:"module"情况下,如何解决这个报错呢?

我们可以单独给某个文件设置后缀名来使用CommonJS 脚本,强制的指定文件后缀为 .cjs

方案2:按照CommonJS 规范,不做任何配置情况下

指定需要使用ES Module 的文件的后缀名为 .mjs,那么这个文件会被强制指定使用 ES Module 规范

方案3:使用 Babel 完美配置 CommonJS 和 ES Module 随心使用(这个目前有更新的配置方案,等我忙完了写到方案4,方案3也可以用哦)

安装依赖
npm install --save-dev babel-cli babel-preset-env babel-register babel-preset-stage-0 
npm install --save babel-polyfill # babel转码时不能识别一些全局对象的API,例如Object.assign,使用它可以解决这个问题
  • babel-polyfill babel转码时不能识别一些全局对象的API
  • babel-preset-stage-0 es阶段性提案语法 stage-0 包含stage1,2,3
  • babel-register 钩子,在程序入口文件引入即可实现转码
在根目录新建 .babelrc

{
    "presets": [
      "env",
      "stage-0"
    ]
  }
配置命令入口,在根目录新建 main.js
require('babel-polyfill');
require('babel-register');
require('./app.js'); // 引入您的项目的启动文件
配置命令行

package.json中加入

"scripts": {
    "start": "node main.js",
  },
启动项目
npm start

大功告成,接下来项目内写任何类型都不会有问题

方案4:等我忙完了,继续补充,确实有更好的方式,可以使用更少的依赖

  • 今天就写到这里啦~
  • 小伙伴们,( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ我们明天再见啦~~
  • 大家要天天开心哦

欢迎大家指出文章需要改正之处~
学无止境,合作共赢

在这里插入图片描述

欢迎路过的小哥哥小姐姐们提出更好的意见哇~~
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 TypeScript 使用 Webpack 可以通过以下步骤来实现在浏览器使用 Node.js 的一些全局对象和方法: 1. 安装依赖:首先需要安装 `webpack` 和 `webpack-cli` 两个依赖。 ``` npm install webpack webpack-cli --save-dev ``` 2. 配置 TypeScript 编译选项:在 `tsconfig.json` 文件,需要将 `target` 选项设置为 `es5` 或更高版本,以支持一些新的 JavaScript 特性。同时,需要将 `module` 选项设置为 `commonjs`,以支持 Node.js 的模块化规范。 ```json { "compilerOptions": { "target": "es5", "module": "commonjs" } } ``` 3. 配置 Webpack:在根目录下创建一个 `webpack.config.js` 文件,用于配置 Webpack。 ```javascript const path = require('path'); module.exports = { mode: 'development', entry: './src/index.ts', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, resolve: { extensions: ['.ts', '.js'] }, module: { rules: [ { test: /\.ts$/, use: 'ts-loader', exclude: /node_modules/ } ] } }; ``` 上述配置文件,`entry` 选项指定了入口文件,`output` 选项指定了打包后的文件名和文件路径,`resolve` 选项指定了可以省略的文件扩展名,`module` 选项的 `rules` 字段指定了处理 TypeScript 文件的 loader。 4. 安装 `ts-loader`:在命令行执行以下命令来安装 `ts-loader`。 ``` npm install ts-loader --save-dev ``` 5. 编写代码:在 `src` 目录下编写 TypeScript 代码,使用 Node.js 的全局对象和方法。 ```typescript import fs from 'fs'; const data = fs.readFileSync('test.txt', 'utf8'); console.log(data); ``` 上述代码使用Node.js 的 `fs` 模块来读取文件,并且使用了 `console.log` 方法来输出数据。 6. 打包代码:在命令行执行以下命令来打包代码。 ``` npx webpack ``` 执行完毕后,会在 `dist` 目录下生成一个 `bundle.js` 文件,可以在浏览器加载使用。需要注意的是,在浏览器使用 Node.js 的全局对象和方法时,需要确保这些方法在浏览器的兼容性和安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值