前端的全栈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通过import和export语法,使得模块化变得更加规范化和易于理解。然而,由于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中编写模块时,只需使用标准的import和export语法,无需担心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模块化方案的优势
-
统一的模块化标准:Deno彻底抛弃了CommonJS,只支持ESM模块,这使得模块化体系变得简单一致,开发者不再需要在CommonJS和ESM之间切换,也避免了常见的
ERR_REQUIRE_ESM错误。 -
与Web兼容:Deno的模块加载方式与浏览器保持一致,使用URL或相对路径加载模块,并且必须显式指定文件扩展名。这种方式使得代码在Deno和浏览器之间的互操作性更强,减少了跨环境迁移的障碍。
-
内置TypeScript支持:Deno直接支持TypeScript,无需额外的配置或编译工具,这使得现代JavaScript开发更加方便,开发者可以充分利用TypeScript的类型系统来提高代码的可靠性。
-
模块管理简化:通过直接使用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搜索功能与订阅支付指南
就在凌晨,在ChatGPT迎来两周岁生日之际,OpenAI重磅发布了ChatGPT的全新人工智能搜索体验。 期待已久的时刻终于到来, ChatGPT正式转型成为一款革命性的AI搜索引擎! 先来看看ChatGPT搜索:这次不是简单的加个搜索框,而…...
【植物识别】Python+深度学习+人工智能+CNN卷积神经网络+算法模型训练+TensorFlow
一、介绍 植物识别系统,使用Python作为主要编程语言开发,通过收集常见的6中植物树叶(‘广玉兰’, ‘杜鹃’, ‘梧桐’, ‘樟叶’, ‘芭蕉’, ‘银杏’)图片作为数据集,然后使用TensorFlow搭建ResNet50算法网络模型&am…...
快讯,Flutter PC 多窗口新进展,已在 Ubuntu/Canonical 展示
相信 Flutter 开发者对于 Flutter PC 多窗口的支持一直是「望眼欲穿」,而根据 #142845 相关内容展示, 在上月 27 号的 Ubuntu 峰会,Flutter 展示了多窗口相关进展。 事实上 Ubuntu 和 Flutter 的进一步合作关系应该是在 2021 年就开始了&…...
BigDecimal 详解
阿里巴巴 Java 开发手册》中提到:“为了避免精度丢失,可以使用 BigDecimal 来进行浮点数的运算”。 浮点数的运算竟然还会有精度丢失的风险吗?确实会! 示例代码: float a 2.0f - 1.9f; float b 1.8f - 1.7f; Syst…...
ESP-HaloPanel:用 ESP32-C2 打造超低成本智能家居面板
项目简介 在生活品质日益提升的今天,智能家居系统已经走进了千家万户,并逐渐成为现代生活的一部份。与此同时,一款设计精致、体积轻盈、操作简便的全屋智能家居控制面板,已经成为众多家庭的新宠。这种高效、直观的智能化的解决方…...
CSS3新增盒子属性(三)
1、CSS3新增盒子属性 1.1 box-sizing 设置盒子的大小。 content-box:设置内容区的大小;border-box:设置盒子的总大小。 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><t…...
Manus在虚拟现实仿真模拟中的应用案例分享
Manus虚拟现实手套作为一种高精度的人机交互设备,在仿真模拟领域展现出了巨大的应用潜力。通过提供实时、准确的手指动作捕捉数据,Manus手套为多个行业带来了前所未有的仿真体验,推动了技术发展和应用创新。 技术特点 1. 高精度手指跟踪 Ma…...
大数据-201 数据挖掘 机器学习理论 - 决策树 局部最优 剪枝 分裂 二叉分裂
点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...
Scala 的trait
在Scala中,trait是一种特殊概念。trait可以作为接口,同时也可以定义抽象方法。类使用extends继承trait,在Scala中,无论继承类还是继承trait都用extends关键字。在Scala中, 类继承trait后必须实现其中的抽象方法&#x…...
vue3官方示例-简单的 markdown 编辑器。
官方示例不能直接粘贴使用,故自己补了些代码。方便初学者学习,节省时间,提高学习效率。 1、html代码: <!doctype html> <html lang"en"> <head><meta charset"UTF-8"><meta nam…...
Linux标准I/O库汇总整理
Linux标准I/O库(Standard I/O Library)是C标准库的一部分,提供了一系列用于文件输入输出的高级接口。这些接口通常比低级别的系统调用更易于使用,但也可能带来额外的性能开销。下面是Linux标准I/O库的汇总整理,包括常见…...
BGP路由优选+EVPN
BGP 的路由优选规则是一套多步决策链,用来确定在多个可行路由中选择最优的路由。BGP 是一种路径向量协议,通过这些优选规则,网络管理员可以控制数据流量的流向,确保网络的稳定性和效率。下面以一个实例来详细说明 BGP 的优选规则及…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
实战三:开发网页端界面完成黑白视频转为彩色视频
一、需求描述 设计一个简单的视频上色应用,用户可以通过网页界面上传黑白视频,系统会自动将其转换为彩色视频。整个过程对用户来说非常简单直观,不需要了解技术细节。 效果图 二、实现思路 总体思路: 用户通过Gradio界面上…...
