当前位置: 首页 > Web前端 > JavaScript

可能改变前端工程未来的特性:ESMLoaderHooks

时间:2023-03-27 14:18:15 JavaScript

大家好,我是Kason。在最近发布的Nodev18.6.0中,引入了一个实验性的特性ESMLoaderHooksAPI。如果他最终落地,很可能会成为改变前端工程未来的一个特性。这篇文章就来说说他吧。欢迎加入人类优质前端框架群,将本文作为参考:CustomESMloaders:Who,what,when,where,why,how特性介绍用过webpack的朋友一定知道有是webpack中loader的一个概念,用来加载和处理不同类型的文件,比如css-loader,url-loader。loader的执行顺序取决于webpack内部解析和遍历文件树的顺序。今天要介绍的ESMLoaderHooks和webpackloader类似,只是文件树的解析和遍历是由Node.js原生支持的ESM规范决定的(而不是打包工具)。通过定义不同的加载器,可以在不使用工程工具的情况下处理项目中的每个ESM模块。例如在命令行通过--experimental-loader命令启用该特性后,执行如下语句:$>node--loaderredirect.mjsapp.mjs其中,app.mjs为待处理的源文件,而.mjs后缀指的是文件表示为ESM模块(对应的,.cjs后缀指的是CJS模块)。--loader用于指定一个自定义的ESMLoader,这里指定redirect.mjs,app.mjs会被redirect.mjs处理。redirect.mjs代码如下://redirect.mjsexportfunctionresolve(specifier,context,nextResolve){letredirect='app.prod.mjs';switch(process.env.NODE_ENV){case'development':redirect='app.dev.mjs';休息;case'test':redirect='app.test.mjs';休息;}returnnextResolve(redirect);}redirect.mjs会根据Node当前环境重写文件导入路径。比如在开发环境中(process.env.NODE_ENV==='development'),app.mjs经过redirect.mjs处理后会重定向到app.dev.mjs。ESMLoaderHooksAPI中之所以有Hooks,是因为每个自定义ESMLoader都可以像钩子(Hooks)一样连接到其他自定义ESMLoader(或者Node.js默认提供的ESMLoader)。例如,在下面的语句中:$>node--loaderc.mjs--loaderb.mjs--loadera.mjsapp.mjsapp.mjs将依次被三个自定义的ESMLoaderabc处理。整个过程就像一个promise.then链(事实上,每个ESM加载器确实返回一个promise)。实际示例要查看更接近日常开发的示例,请考虑以下ESM模块://app.tsximportReactDOMfrom'react-dom/client';import{BrowserRouter,useRoutes,}from'react-router-dom';importApp来自'./AppHeader.tsx';从'https://example.com/routes.json'导入路由断言{type:'json'};import'./global.css'assert{type:'css'};constroot=ReactDOM.createRoot(document.getElementById('root'));root.render(

{useRoutes(路由)}
);其中包括很多Node.js无法处理的部分,例如:TS语法(需要编译成JS,并将文件描述符处理成Node.js可识别的形式)JSX转换(需要编译成React.createElement或jsxRuntime.jsx)需要处理导入CSS文件需要处理远程导入的模块(代码中引入路由的语句)处理CSS文件处理CSS文件。例如,假设CSS文件内容如下:.Container{border:1pxsolidblack;}.SomeInnerPiece{background-color:blue;}为了测试,只需要生成对应类的快照名称,因此可以实现一个简单的CSS加载器来处理输入的CSS文件并将结果输出为Node.js可执行的JSON格式:{"Container":"Container","SomeInnerPiece":"SomeInnerPiece"}参考:简单实现处理远程导入模块的CSS加载器我们以处理远程导入的模块为例。当识别到以https://开头的文件描述符(即import语句或import()表达式中的字符串部分)时,可以使用https模块发起请求,请求对应的promise为回。:从'https'导入{get};exportfunctionload(url,context,nextLoad){if(url.startsWith('https://')){returnnewPromise((resolve,reject)=>{get(url,(res)=>{让数据='';res.on('data',chunk=>data+=chunk);res.on('end',()=>resolve({format:'module',shortCircuit:true,source:data,}));}).on('错误',err=>reject(err));});}returnnextLoad(url,context);}参考:httpsloader简单实现小结当ESMLoaderHooks特性趋于稳定,配套的loader生态足够丰富时,很多原本需要打包工具才能实现的工程需求可以使用Node.js本地解决。例如,要处理上面提到的app.tsx文件,只需执行以下命令:$>node--loadertypescript-loader--loadercss-loader--loadernetwork-loaderapp.tsx你觉得这个特性有用吗对未来前端工程有多大影响?