当前位置: 首页 > news >正文

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

在现代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中编写的代码可以很方便地移植到浏览器环境中,而无需进行额外的改动。

插一嘴,如果没有写扩展名,默认是js - 这时候可以绕过一些检测机制,例如针对文本的加密等

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/std@0.113.0/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,相信它会为你带来耳目一新的体验。

相关文章:

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

在现代JavaScript开发中,模块化系统的演变经历了多次变革,使得前端和后端开发人员在选择模块加载方式时常常感到困惑。尤其是Node.js所采用的CommonJS和ESM(ECMAScript Modules)两种模块体系,以及文件扩展名的多样性&a…...

与外部公司做数据交互时,需要注意哪些事情?

在现代企业系统中,数据交互已成为日常业务流程的核心部分。与外部公司进行数据交换可以带来业务合作和资源共享的机会,但也带来了数据安全、协议兼容性、合规性等方面的挑战。本文将深入探讨在与外部公司进行数据交互时需要关注的关键事项,并…...

基于hive分析Flask为后端框架echarts为前端框架的招聘网站可视化大屏项目

基于hive分析Flask为后端框架echarts为前端框架的招聘网站可视化大屏项目 1. 项目概述 项目目标是构建一个大数据分析系统,包含以下核心模块: 1、数据爬取:通过request请求获取猎聘网的就业数据。 2、数据存储和分析:使用 Hive …...

Ansible 部署应用

Ansible Ansible 是基于 Python 开发,集合了众多优秀运维工具的优点,实现了批量运行命令、部署程序、配置系统等功能的自动化运维管理工具。默认通过 SSH 协议进行远程命令执行或下发配置,无需部署任何客户端代理软件,从而使得自动…...

使用Docker Swarm进行集群管理

💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 使用Docker Swarm进行集群管理 Docker Swarm简介 安装Docker 在Ubuntu上安装Docker 在CentOS上安装Docker 在macOS上安装Docker …...

基于树莓派的安保巡逻机器人--(一、快速人脸录入与精准人脸识别)

目录 零、前言 一、人脸检测 二、人脸识别 1、采集人脸 2、训练人脸识别模型 3、人脸识别应用 零、前言 随着智能安防需求的增长,基于人工智能和物联网的安保系统逐渐成为趋势。树莓派因其低成本、高扩展性等特点,成为很多AI项目的理想平台。本文将为大…...

中间件的应用

控制器 <?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;class AgeController extends Controller {//public function index(){return "年龄测试";} }路由 // 年龄控制器路由 Route::get("d2/{age}",[AgeController::class,&quo…...

真题与解析 202206二级 青少年软件编程(Python)考级

青少年软件编程(Python)等级考试试卷(二级) 202206真题与解析 分数:100 题数:37 测试时长:60分钟</...

ChatGPT新体验:AI搜索功能与订阅支付指南

就在凌晨&#xff0c;在ChatGPT迎来两周岁生日之际&#xff0c;OpenAI重磅发布了ChatGPT的全新人工智能搜索体验。 期待已久的时刻终于到来&#xff0c; ChatGPT正式转型成为一款革命性的AI搜索引擎! 先来看看ChatGPT搜索&#xff1a;这次不是简单的加个搜索框&#xff0c;而…...

【植物识别】Python+深度学习+人工智能+CNN卷积神经网络+算法模型训练+TensorFlow

一、介绍 植物识别系统&#xff0c;使用Python作为主要编程语言开发&#xff0c;通过收集常见的6中植物树叶&#xff08;‘广玉兰’, ‘杜鹃’, ‘梧桐’, ‘樟叶’, ‘芭蕉’, ‘银杏’&#xff09;图片作为数据集&#xff0c;然后使用TensorFlow搭建ResNet50算法网络模型&am…...

快讯,Flutter PC 多窗口新进展,已在 Ubuntu/Canonical 展示

相信 Flutter 开发者对于 Flutter PC 多窗口的支持一直是「望眼欲穿」&#xff0c;而根据 #142845 相关内容展示&#xff0c; 在上月 27 号的 Ubuntu 峰会&#xff0c;Flutter 展示了多窗口相关进展。 事实上 Ubuntu 和 Flutter 的进一步合作关系应该是在 2021 年就开始了&…...

BigDecimal 详解

阿里巴巴 Java 开发手册》中提到&#xff1a;“为了避免精度丢失&#xff0c;可以使用 BigDecimal 来进行浮点数的运算”。 浮点数的运算竟然还会有精度丢失的风险吗&#xff1f;确实会&#xff01; 示例代码&#xff1a; float a 2.0f - 1.9f; float b 1.8f - 1.7f; Syst…...

ESP-HaloPanel:用 ESP32-C2 打造超低成本智能家居面板

项目简介 在生活品质日益提升的今天&#xff0c;智能家居系统已经走进了千家万户&#xff0c;并逐渐成为现代生活的一部份。与此同时&#xff0c;一款设计精致、体积轻盈、操作简便的全屋智能家居控制面板&#xff0c;已经成为众多家庭的新宠。这种高效、直观的智能化的解决方…...

CSS3新增盒子属性(三)

1、CSS3新增盒子属性 1.1 box-sizing 设置盒子的大小。 content-box&#xff1a;设置内容区的大小&#xff1b;border-box&#xff1a;设置盒子的总大小。 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><t…...

Manus在虚拟现实仿真模拟中的应用案例分享

Manus虚拟现实手套作为一种高精度的人机交互设备&#xff0c;在仿真模拟领域展现出了巨大的应用潜力。通过提供实时、准确的手指动作捕捉数据&#xff0c;Manus手套为多个行业带来了前所未有的仿真体验&#xff0c;推动了技术发展和应用创新。 技术特点 1. 高精度手指跟踪 Ma…...

大数据-201 数据挖掘 机器学习理论 - 决策树 局部最优 剪枝 分裂 二叉分裂

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…...

Scala 的trait

在Scala中&#xff0c;trait是一种特殊概念。trait可以作为接口&#xff0c;同时也可以定义抽象方法。类使用extends继承trait&#xff0c;在Scala中&#xff0c;无论继承类还是继承trait都用extends关键字。在Scala中&#xff0c; 类继承trait后必须实现其中的抽象方法&#x…...

vue3官方示例-简单的 markdown 编辑器。

官方示例不能直接粘贴使用&#xff0c;故自己补了些代码。方便初学者学习&#xff0c;节省时间&#xff0c;提高学习效率。 1、html代码&#xff1a; <!doctype html> <html lang"en"> <head><meta charset"UTF-8"><meta nam…...

Linux标准I/O库汇总整理

Linux标准I/O库&#xff08;Standard I/O Library&#xff09;是C标准库的一部分&#xff0c;提供了一系列用于文件输入输出的高级接口。这些接口通常比低级别的系统调用更易于使用&#xff0c;但也可能带来额外的性能开销。下面是Linux标准I/O库的汇总整理&#xff0c;包括常见…...

BGP路由优选+EVPN

BGP 的路由优选规则是一套多步决策链&#xff0c;用来确定在多个可行路由中选择最优的路由。BGP 是一种路径向量协议&#xff0c;通过这些优选规则&#xff0c;网络管理员可以控制数据流量的流向&#xff0c;确保网络的稳定性和效率。下面以一个实例来详细说明 BGP 的优选规则及…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

day52 ResNet18 CBAM

在深度学习的旅程中&#xff0c;我们不断探索如何提升模型的性能。今天&#xff0c;我将分享我在 ResNet18 模型中插入 CBAM&#xff08;Convolutional Block Attention Module&#xff09;模块&#xff0c;并采用分阶段微调策略的实践过程。通过这个过程&#xff0c;我不仅提升…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…...