首页 > 其他分享 >前端的全栈Deno篇(五):与前端保持一致的模块化方案,摆脱ERR_REQUIRE_ESM和mjs、cjs等模块混乱带来的心智负担

前端的全栈Deno篇(五):与前端保持一致的模块化方案,摆脱ERR_REQUIRE_ESM和mjs、cjs等模块混乱带来的心智负担

时间:2024-11-01 14:50:10浏览次数:4  
标签:CommonJS ERR 模块化 前端 js 全栈 Deno 模块 ESM

在现代JavaScript开发中,模块化系统的演变经历了多次变革,使得前端和后端开发人员在选择模块加载方式时常常感到困惑。尤其是Node.js所采用的CommonJS和ESM(ECMAScript Modules)两种模块体系,以及文件扩展名的多样性(如.cjs.mjs.js)带来的复杂性和混乱。Deno的诞生以及其2.0版本带来的模块化系统,正试图解决这些问题,并为开发者提供一种更统一、符合Web标准的模块化方案。

写这篇文章的原因就是,今天使用llamaindex,被其混乱的第三方模块折腾麻了,本来只是简单测试,后面不得不改了模块类型,都是因为cjs和ejs混用导致的,而且 cjs和mjs模块的导入需要加后缀!简直不可忍受

Node.js模块化系统的演变与挑战

Node.js最早采用的模块化方案是CommonJS,这是为了让开发者能够在Node环境中编写模块化代码而提出的方案。通过require()方法,CommonJS实现了模块的导入与导出。然而,这种模块化方式是基于服务器端环境而设计的,与浏览器中的模块加载机制存在较大差异。

随着ES6(也称为ES2015)的发布,JavaScript正式引入了标准化的模块化机制——ESM(ECMAScript Modules)。ESM通过importexport语法,使得模块化变得更加规范化和易于理解。然而,由于Node.js在最初阶段只支持CommonJS,导致这两种模块化方案在Node.js中长期共存。

在Node.js中,当使用ESM模块时,需要使用文件扩展名.mjs或者在package.json中指定"type": "module",而CommonJS模块通常使用.cjs扩展名或默认的.js扩展名。这种双重模块系统的存在,给开发者带来了很多困扰。例如,如果试图在CommonJS模块中使用import语法,或者在ESM模块中使用require(),往往会遇到类似ERR_REQUIRE_ESM的错误。

此外,Node.js对文件扩展名的处理也较为复杂,开发者需要记住何时需要显式指定文件扩展名,何时可以省略,这增加了代码的维护成本和理解难度。这种模块化系统的混乱现状,让很多开发者在使用第三方库、集成旧代码时遇到许多阻碍。

Node.js中的模块化代码示例

以下是Node.js中使用CommonJS和ESM的示例:

CommonJS示例(require()方式):

// commonjs-module.js
module.exports = function() {
  console.log("Hello from CommonJS");
};
// main.js (CommonJS)
const greet = require("./commonjs-module");
greet();

CommonJS示例(导入导出对象):

// commonjs-object-module.cjs
const greetings = {
  greetEnglish: function() {
    console.log("Hello from CommonJS");
  },
  greetSpanish: function() {
    console.log("Hola desde CommonJS");
  }
};

module.exports = greetings;
// main.cjs (CommonJS)
const greetings = require("./commonjs-object-module.cjs"); // 一定要加.cjs后缀
greetings.greetEnglish();
greetings.greetSpanish();

ESM示例(import方式):

// esm-module.mjs
export function greet() {
  console.log("Hello from ESM");
}
// main.mjs
import { greet } from "./esm-module.mjs";
greet();

在Node.js中,必须根据模块类型选择适当的加载方式,否则可能会遇到各种错误。

Deno的统一模块化方案

为了解决这些痛点,Deno引入了一种更加现代化、统一的模块化系统,并且严格遵循Web标准。Deno最初的设计目标之一就是摆脱Node.js的历史包袱,避免其模块化系统中的种种复杂性。

Web标准的模块化方式

Deno采用了原生的ESM作为其模块系统,彻底抛弃了CommonJS,这意味着开发者在Deno中编写模块时,只需使用标准的importexport语法,无需担心CommonJS和ESM之间的兼容问题。这样一来,代码的可读性和可维护性得到了极大提升。

此外,Deno要求模块必须通过URL或相对路径来加载,并且所有的模块文件都需要明确指定扩展名(例如.js.ts等)。这种设计与浏览器的模块加载方式保持了一致,使得在Deno中编写的代码可以很方便地移植到浏览器环境中,而无需进行额外的改动。

Deno还内置了对TypeScript的支持,开发者可以直接编写TypeScript代码,而不需要额外的编译步骤。这种内置支持使得TypeScript的使用更加自然,并且与ESM的模块化机制无缝集成。

Deno中的模块化代码示例

以下是Deno中使用ESM的示例:

使用ESM的Deno示例:

// greet.ts
export function greet() {
  console.log("Hello from Deno");
}
// main.ts
import { greet } from "./greet.ts";
greet();

在Deno中,模块的加载方式与浏览器类似,文件扩展名必须明确指定。这使得代码更加直观,也更符合开发者的预期。

模块管理的现代化

与Node.js依赖npm来管理模块不同,Deno没有中央的包管理工具,而是采用URL来直接引入第三方模块。这种方式借鉴了Web的资源加载方式,使得模块的获取过程更加透明和简单,开发者可以直接通过URL查看模块的源代码。这种模块管理方式避免了传统包管理器中的“依赖地狱”,并且使得项目的依赖关系更加清晰。

以下是Deno中通过URL加载第三方模块的示例:

import { serve } from "https://deno.land/[email protected]/http/server.ts";

const handler = (request: Request): Response => {
  return new Response("Hello from Deno server!", { status: 200 });
};

serve(handler);

通过URL加载模块的方式,使得开发者可以清楚地看到模块的来源,并且减少了对包管理器的依赖。

此外,Deno 2.0引入了deno.json配置文件,使得开发者可以更加灵活地配置项目,类似于Node.js中的package.json,但更加简洁和统一。通过这种配置文件,开发者可以指定TypeScript编译选项、模块路径别名等,从而进一步提高开发体验。

Deno模块化方案的优势

  1. 统一的模块化标准:Deno彻底抛弃了CommonJS,只支持ESM模块,这使得模块化体系变得简单一致,开发者不再需要在CommonJS和ESM之间切换,也避免了常见的ERR_REQUIRE_ESM错误。

  2. 与Web兼容:Deno的模块加载方式与浏览器保持一致,使用URL或相对路径加载模块,并且必须显式指定文件扩展名。这种方式使得代码在Deno和浏览器之间的互操作性更强,减少了跨环境迁移的障碍。

  3. 内置TypeScript支持:Deno直接支持TypeScript,无需额外的配置或编译工具,这使得现代JavaScript开发更加方便,开发者可以充分利用TypeScript的类型系统来提高代码的可靠性。

  4. 模块管理简化:通过直接使用URL加载模块,Deno减少了对包管理器的依赖,避免了包版本冲突等问题,同时也让模块的来源变得更加透明。

总结

Node.js的模块化系统在历史上经历了从CommonJS到ESM的演变,但这种演变带来的兼容性问题和复杂的文件扩展名规则,给开发者带来了很多困扰。而Deno通过采用统一的ESM模块化方案,严格遵循Web标准,彻底解决了这些问题。Deno的2.0版本更是通过deno.json等配置进一步提升了开发者的体验。

对于前端和全栈开发者来说,Deno提供了一种现代化、简洁而统一的开发体验,不再需要为模块化的复杂性而烦恼。它让开发者能够更加专注于代码本身,而不是被各种历史遗留的模块化问题所困扰。如果你还在为Node.js中的模块化混乱而烦恼,不妨尝试一下Deno,相信它会为你带来耳目一新的体验。

标签:CommonJS,ERR,模块化,前端,js,全栈,Deno,模块,ESM
From: https://blog.csdn.net/m0_38015699/article/details/143428693

相关文章

  • WebSocket详解:从前端到后端的全栈理解
    文章目录前言一、WebSocket简介1.1WebSocket的特点二、WebSocket的工作原理2.1握手过程2.2数据传输三、WebSocket在前端的应用四、WebSocket在后端的应用五、WebSocket的局限与解决方案结语前言随着互联网技术的发展,传统的HTTP协议在某些场景下的局限性逐渐显......
  • 前端面试看似普遍却热度最高的题
    一、说一下浏览器事件模型1、Dom0级别简单直接,html属性上添加事件函数<buttononclick="handleClick()">Clickme</button>2、Dom1级别Dom1只是一个规范标准,但并没有明确地引入新的事件模型规范3、Dom2级别特点:引入了更强大、更规范的事件处理机制。支持事件的捕......
  • 在K8S中,pod 状态为 ErrlmagePull 如何解决?
    在Kubernetes(K8S)中,当Pod的状态显示为ErrImagePull时,这通常意味着Kubernetes集群无法从配置的镜像仓库中拉取(pull)容器镜像。要解决这个问题,可以按照以下步骤进行详细的排查和解决:1.检查镜像仓库和镜像地址镜像仓库地址:确认Pod定义中指定的镜像仓库地址是否正确,包括仓库的URL......
  • 0-petalinux 问题记录-VFS: Cannot open root device fs or unknown-block(0,0): erro
    0-petalinux问题记录-VFS:Cannotopenrootdevicefsorunknown-block(0,0):error-6这个问题是对SD卡分区之后,ext4分区写入一个文件系统之后的现象,不能正常启动,通过log可以看出来是能找到sd卡的分区,提示需要增加引导,可是在镜像构建的时候UBoot那里面已经设置过了,参数没......
  • 0-petalinux 问题记录-VFS: Cannot open root device fs or unknown-block(0,0): erro
    0-petalinux问题记录-VFS:Cannotopenrootdevicefsorunknown-block(0,0):error-6这个问题是对SD卡分区之后,ext4分区写入一个文件系统之后的现象,不能正常启动,通过log可以看出来是能找到sd卡的分区,提示需要增加引导,可是在镜像构建的时候UBoot那里面已经设置过了,参数没......
  • 【前端基础】CSS基础
    目标:掌握CSS属性基本写法,能够使用文字相关属性美化文章页。01-CSS初体验层叠样式表(CascadingStyleSheets,缩写为CSS),是一种样式表语言,用来描述HTML文档的呈现(美化内容)。书写位置:title标签下方添加style双标签,style标签里面书写CSS代码。<title>CSS初......
  • 【前端基础】CSS进阶
    目标:掌握复合选择器作用和写法;使用background属性添加背景效果01-复合选择器定义:由两个或多个基础选择器,通过不同的方式组合而成。作用:更准确、更高效的选择目标元素(标签)。后代选择器后代选择器:选中某元素的后代元素。选择器写法:父选择器子选择器{CSS属性},父子......
  • Dedecms后台 Fatal error:Allowed memory size of 8388608 bytes 提示的解决方法
    修改 .htaccess 文件在 .htaccess 文件的最上面添加:php_valuemax_execution_time1200php_valuememory_limit200Mphp_valuepost_max_size200Mphp_valueupload_max_filesize200M修改 php.ini 文件将 memory_limit 的值从 8M 改为 12M 或更......
  • Linux操作系统网站提示“Internal Server Error”报错
    可能原因及解决方法服务器资源超载解决方法:检查服务器资源使用情况,如CPU、内存和磁盘空间。如果资源使用率过高,考虑优化应用或升级服务器配置。PHP版本过低解决方法:检查当前PHP版本,并确保与WordPress兼容。可以通过以下命令查看PHP版本:   PHP文件配置错......
  • 后台业务系统OA,CRM,ERP,HR这类开发用什么前端UI框架更好
    在开发后台业务系统如OA、CRM、ERP和HR时,选择合适的前端UI框架至关重要。本文主要探讨:一、Bootstrap框架;二、AntDesign框架;三、ElementUI框架;四、Vue.js框架;五、React框架。考虑到这些系统的复杂性和对界面的要求,以下框架能够提供高效、统一和用户友好的体验。一、Bootstrap......