mirror of
https://github.com/ZiuChen/ZiuChen.github.io.git
synced 2025-08-17 23:19:55 +08:00
424 lines
176 KiB
JavaScript
424 lines
176 KiB
JavaScript
import{_ as s,o as n,c as a,Q as l}from"./chunks/framework.9b71bc06.js";const o="/assets/the-node.js-system.dd187a1f.jpeg",p="/assets/esmodule-phases.7bb37c77.png",e="/assets/hard-link-and-soft-link.b45d1c8a.jpg",c="/assets/how-pnpm-works.a14a4880.jpg",g=JSON.parse('{"title":"前端工程化","description":"","frontmatter":{},"headers":[],"relativePath":"note/Front-end Engineering.md","filePath":"note/Front-end Engineering.md","lastUpdated":1704524259000}'),r={name:"note/Front-end Engineering.md"},t=l('<h1 id="前端工程化" tabindex="-1">前端工程化 <a class="header-anchor" href="#前端工程化" aria-label="Permalink to "前端工程化""></a></h1><h2 id="node-js" tabindex="-1">Node.js <a class="header-anchor" href="#node-js" aria-label="Permalink to "Node.js""></a></h2><ul><li>什么是Node.JS Node的应用场景</li><li>JS代码执行</li><li>Node的输入和输出</li><li>Node的全局对象</li></ul><h3 id="什么是node-js" tabindex="-1">什么是Node.js <a class="header-anchor" href="#什么是node-js" aria-label="Permalink to "什么是Node.js""></a></h3><p>Node.js是一个基于<strong>V8 JavaScript引擎</strong>的<strong>JavaScript运行时环境</strong></p><ul><li>V8可以嵌入到任何C++应用程序中,无论是Chrome还是Node.js,事实上都嵌入了V8引擎来执行JavaScript代码</li><li>在Chrome浏览器中,还需要解析、渲染HTML、CSS等相关渲染引擎,另外还需要支持浏览器操作的API、浏览器自己的事件循环</li><li>在Node.js中我们也需要进行一些额外操作:文件系统读写、网络IO、加密、压缩解压文件等</li></ul><p>可以简单总结出Node.js和浏览器的区别</p><ul><li><p>Chrome浏览器</p><ul><li><p>Blink负责解析HTML文档,遇到JavaScript标签时将内容交给V8引擎</p></li><li><blockquote><p>Blink 是 Google Chrome 浏览器的渲染引擎,V8 是 Blink 内置的 JavaScript 引擎</p></blockquote><ul><li>预分析:检查语法错误但不生成AST树</li><li>生成AST:语法分析、词法分析后,生成抽象语法树(AST) <ul><li>AST 为每一行代码定义键值对。初始类型标识符定义 AST 属于一个程序,然后所有代码行将定义在主体内部,主体是一个对象数组。</li></ul></li><li>生成字节码:基线编译器(Ignition)将 AST 转换为字节码</li><li>生成机器代码:优化编译器 (Turbofan) 将字节码转换为优化的机器代码。另外,在逐行执行字节码的过程中,<strong>如果一段代码经常被执行,V8会直接将这段代码转换并保存为机器码</strong>,下次执行不需要经过字节码,优化了执行速度</li></ul></li></ul></li><li><p>Node.js</p><ul><li>只处理JavaScript代码 内部V8引擎负责JS代码的执行</li><li>JavaScript代码 -> V8 -> Node.js Bindings -> LibUV</li><li>LibUV是使用<strong>C语言编写的库</strong>,提供了<strong>事件循环、文件系统读写、网络IO、线程池</strong>等等内容</li></ul></li></ul><p><img src="'+o+`" alt="The Node.js System"></p><h3 id="node-js的应用场景" tabindex="-1">Node.js的应用场景 <a class="header-anchor" href="#node-js的应用场景" aria-label="Permalink to "Node.js的应用场景""></a></h3><ul><li>前端开发的库都是以node包形式管理的</li><li>npm yarn pnpm成为前端开发使用最多的工具</li><li>使用Node.js作为Web服务器开发、中间件、代理服务器</li><li>借助Node.js完成前后端渲染的同构应用</li><li>编写脚本工具 构建项目 打包代码等</li><li>Electron桌面应用程序</li></ul><h3 id="node-js的参数传递" tabindex="-1">Node.js的参数传递 <a class="header-anchor" href="#node-js的参数传递" aria-label="Permalink to "Node.js的参数传递""></a></h3><h4 id="process-argv" tabindex="-1"><code>process.argv</code> <a class="header-anchor" href="#process-argv" aria-label="Permalink to "\`process.argv\`""></a></h4><p><code>process.argv</code>返回一个数组</p><ul><li>在代码中通过<code>process.argv[2]</code>读取来自命令行的额外参数</li><li><code>process.argv[0]</code> <code>process.argv[1]</code>分别为<code>node.exe</code>的绝对路径和<code>目标文件</code>的绝对路径</li></ul><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// sum.js</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">x</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> process.argv[</span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">]</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">y</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> process.argv[</span><span style="color:#79B8FF;">3</span><span style="color:#E1E4E8;">]</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(x </span><span style="color:#F97583;">+</span><span style="color:#E1E4E8;"> y)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// sum.js</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">x</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> process.argv[</span><span style="color:#005CC5;">2</span><span style="color:#24292E;">]</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">y</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> process.argv[</span><span style="color:#005CC5;">3</span><span style="color:#24292E;">]</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(x </span><span style="color:#D73A49;">+</span><span style="color:#24292E;"> y)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;"># 通过命令行运行node执行脚本 并传入参数</span></span>
|
||
<span class="line"><span style="color:#B392F0;">node</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">sum.js</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">5</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">10</span><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;"># 15</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;"># 通过命令行运行node执行脚本 并传入参数</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">node</span><span style="color:#24292E;"> </span><span style="color:#032F62;">sum.js</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">5</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">10</span><span style="color:#24292E;"> </span><span style="color:#6A737D;"># 15</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h4 id="console" tabindex="-1">console <a class="header-anchor" href="#console" aria-label="Permalink to "console""></a></h4><ul><li><code>console.log</code> 打印内容到stdout并加上换行符</li><li><code>console.clear</code> 清空当前stdout中的内容</li><li><code>console.trace</code> 打印字符串<code>Trace: </code>到stderr <ul><li>将堆栈跟踪打印到代码中的当前位置</li></ul></li></ul><h4 id="repl" tabindex="-1">REPL <a class="header-anchor" href="#repl" aria-label="Permalink to "REPL""></a></h4><p>在浏览器的控制台选项卡中,我们可以通过输入JS代码与之交互,在Node.js中同样提供了类似的功能</p><ul><li>REPL是Read-Eval-Print Loop的简称,翻译为:读取-求值-输出循环</li><li>REPL是一个<strong>简单的、交互式的编程环境</strong></li><li>在命令行窗口中输入<code>node</code>即可进入</li></ul><h3 id="node中的全局对象" tabindex="-1">Node中的全局对象 <a class="header-anchor" href="#node中的全局对象" aria-label="Permalink to "Node中的全局对象""></a></h3><p>在浏览器中,我们可以在JS代码中访问全局对象<code>window</code>,代表当前标签窗口</p><p>在Node.js中的全局对象名为<code>global</code>,在控制台输出<code>global</code>对象:</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">></span><span style="color:#E1E4E8;"> global</span></span>
|
||
<span class="line"><span style="color:#F97583;"><</span><span style="color:#E1E4E8;">ref </span><span style="color:#F97583;">*1></span><span style="color:#E1E4E8;"> Object [global] {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">global:</span><span style="color:#E1E4E8;"> [Circular </span><span style="color:#79B8FF;">*</span><span style="color:#9ECBFF;">1],</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">clearInterval:</span><span style="color:#E1E4E8;"> [Function: </span><span style="color:#9ECBFF;">clearInterval],</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">clearTimeout:</span><span style="color:#E1E4E8;"> [Function: </span><span style="color:#9ECBFF;">clearTimeout],</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">setInterval:</span><span style="color:#E1E4E8;"> [Function: </span><span style="color:#9ECBFF;">setInterval],</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">setTimeout:</span><span style="color:#E1E4E8;"> [Function: </span><span style="color:#9ECBFF;">setTimeout]</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">{</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> [Symbol(nodejs.util.promisify.custom)]</span><span style="color:#79B8FF;">:</span><span style="color:#E1E4E8;"> [Getter]</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">queueMicrotask:</span><span style="color:#E1E4E8;"> [Function: </span><span style="color:#9ECBFF;">queueMicrotask],</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">performance:</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">Performance</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">{</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">nodeTiming:</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">PerformanceNodeTiming</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">{</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">name:</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'node',</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">entryType:</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'node',</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">startTime:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">0</span><span style="color:#9ECBFF;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">duration:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">2245.9675999991596</span><span style="color:#9ECBFF;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">nodeStart:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">1.7120999991893768</span><span style="color:#9ECBFF;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">v8Start:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">7.749699998646975</span><span style="color:#9ECBFF;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">bootstrapComplete:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">56.47019999846816</span><span style="color:#9ECBFF;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">environment:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">28.44789999909699</span><span style="color:#9ECBFF;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">loopStart:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">97.62589999847114</span><span style="color:#9ECBFF;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">loopExit:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">-1,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">idleTime:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">2070.0206</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">timeOrigin:</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">1675854922619.539</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">clearImmediate:</span><span style="color:#E1E4E8;"> [Function: </span><span style="color:#9ECBFF;">clearImmediate],</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">setImmediate:</span><span style="color:#E1E4E8;"> [Function: </span><span style="color:#9ECBFF;">setImmediate]</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">{</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> [Symbol(nodejs.util.promisify.custom)]</span><span style="color:#79B8FF;">:</span><span style="color:#E1E4E8;"> [Getter]</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> }</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">></span><span style="color:#24292E;"> global</span></span>
|
||
<span class="line"><span style="color:#D73A49;"><</span><span style="color:#24292E;">ref </span><span style="color:#D73A49;">*1></span><span style="color:#24292E;"> Object [global] {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">global:</span><span style="color:#24292E;"> [Circular </span><span style="color:#005CC5;">*</span><span style="color:#032F62;">1],</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">clearInterval:</span><span style="color:#24292E;"> [Function: </span><span style="color:#032F62;">clearInterval],</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">clearTimeout:</span><span style="color:#24292E;"> [Function: </span><span style="color:#032F62;">clearTimeout],</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">setInterval:</span><span style="color:#24292E;"> [Function: </span><span style="color:#032F62;">setInterval],</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">setTimeout:</span><span style="color:#24292E;"> [Function: </span><span style="color:#032F62;">setTimeout]</span><span style="color:#24292E;"> </span><span style="color:#032F62;">{</span></span>
|
||
<span class="line"><span style="color:#24292E;"> [Symbol(nodejs.util.promisify.custom)]</span><span style="color:#005CC5;">:</span><span style="color:#24292E;"> [Getter]</span></span>
|
||
<span class="line"><span style="color:#24292E;"> },</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">queueMicrotask:</span><span style="color:#24292E;"> [Function: </span><span style="color:#032F62;">queueMicrotask],</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">performance:</span><span style="color:#24292E;"> </span><span style="color:#032F62;">Performance</span><span style="color:#24292E;"> </span><span style="color:#032F62;">{</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">nodeTiming:</span><span style="color:#24292E;"> </span><span style="color:#032F62;">PerformanceNodeTiming</span><span style="color:#24292E;"> </span><span style="color:#032F62;">{</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">name:</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'node',</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">entryType:</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'node',</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">startTime:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">0</span><span style="color:#032F62;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">duration:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">2245.9675999991596</span><span style="color:#032F62;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">nodeStart:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">1.7120999991893768</span><span style="color:#032F62;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">v8Start:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">7.749699998646975</span><span style="color:#032F62;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">bootstrapComplete:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">56.47019999846816</span><span style="color:#032F62;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">environment:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">28.44789999909699</span><span style="color:#032F62;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">loopStart:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">97.62589999847114</span><span style="color:#032F62;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">loopExit:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">-1,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">idleTime:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">2070.0206</span></span>
|
||
<span class="line"><span style="color:#24292E;"> },</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">timeOrigin:</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">1675854922619.539</span></span>
|
||
<span class="line"><span style="color:#24292E;"> },</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">clearImmediate:</span><span style="color:#24292E;"> [Function: </span><span style="color:#032F62;">clearImmediate],</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">setImmediate:</span><span style="color:#24292E;"> [Function: </span><span style="color:#032F62;">setImmediate]</span><span style="color:#24292E;"> </span><span style="color:#032F62;">{</span></span>
|
||
<span class="line"><span style="color:#24292E;"> [Symbol(nodejs.util.promisify.custom)]</span><span style="color:#005CC5;">:</span><span style="color:#24292E;"> [Getter]</span></span>
|
||
<span class="line"><span style="color:#24292E;"> }</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br></div></div><h4 id="常见的全局对象" tabindex="-1">常见的全局对象 <a class="header-anchor" href="#常见的全局对象" aria-label="Permalink to "常见的全局对象""></a></h4><ul><li><code>Buffer</code></li><li><code>clearImmediate</code></li><li><code>clearInterval</code></li><li><code>clearTimeout</code></li><li><code>console</code><ul><li>和控制台交互</li></ul></li><li><code>process</code><ul><li>提供了Node进程中相关的信息</li><li>Node的运行环境、系统环境变量、参数等</li></ul></li><li><code>queueMicrotask(callback)</code></li><li><code>setImmediate(callback, [, ...args])</code></li><li><code>setInterval(callback, delay[, ...args])</code></li><li><code>setTimeout(callback, delay[, ...args])</code></li><li><code>TextDecoder</code></li><li><code>TextEncoder</code></li><li><code>URL</code></li><li><code>URLSearchParams</code></li><li><code>WebAssembly</code></li></ul><h4 id="特殊的全局对象" tabindex="-1">特殊的全局对象 <a class="header-anchor" href="#特殊的全局对象" aria-label="Permalink to "特殊的全局对象""></a></h4><p><code>__dirname</code> <code>__filename</code> <code>exports</code> <code>module</code> <code>require()</code></p><ul><li>这些变量看起来是全局的,其实并不是(它们仅存在于模块范围内),只是每个模块中都有</li><li>它们在命令行交互中是不可使用的</li><li><code>__dirname</code> 当前模块的目录名</li><li><code>__filename</code> 当前模块的文件名</li><li><code>exports</code> <code>module</code> <code>require()</code>将在模块章节中讲解</li></ul><h4 id="global对象" tabindex="-1"><code>global</code>对象 <a class="header-anchor" href="#global对象" aria-label="Permalink to "\`global\`对象""></a></h4><p><code>global</code>是一个全局对象</p><ul><li>在Node.js环境下,之前的 <code>process</code> <code>console</code> <code>setTimeout</code>等都有被放入到<code>global</code>中</li><li>而在浏览器中,这些全局API是被放到<code>window</code>对象上的</li></ul><p>这无异于增加了开发者的心智负担,所以在最新的ECMA标准中出现了<code>globalThis</code>,指向全局对象</p><ul><li>在浏览器中的<code>globalThis</code>指向<code>window</code>对象</li><li>在Node.js中的<code>globalThis</code>指向<code>global</code>对象</li></ul><p>两个全局对象的区别:在浏览器中通过<code>var</code>定义的变量会被放到<code>window</code>对象上,而Node.js不会</p><h2 id="模块化开发" tabindex="-1">模块化开发 <a class="header-anchor" href="#模块化开发" aria-label="Permalink to "模块化开发""></a></h2><ul><li>认识模块化开发</li><li>CommonJS和Node</li><li>require函数解析</li><li>AMD和CMD(已经被时代淘汰 了解即可)</li><li>ESModule用法详解</li><li>ESModule运行原理</li></ul><h3 id="模块化的初衷" tabindex="-1">模块化的初衷 <a class="header-anchor" href="#模块化的初衷" aria-label="Permalink to "模块化的初衷""></a></h3><ul><li>将大的程序拆分成一个个小的易于维护的代码</li><li>每个模块负责程序中的一部分逻辑,拥有<strong>自己的作用域</strong>、<strong>定义变量名时不会发生冲突</strong></li><li>模块可以暴露<strong>变量、函数、对象</strong>等导出</li><li>模块可以导入其他模块的<strong>变量、函数、对象</strong></li></ul><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// moduleA.js</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">moduleA</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> (</span><span style="color:#F97583;">function</span><span style="color:#E1E4E8;">(){</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">name</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">"Ziu"</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">age</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">18</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">run</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> () </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(name </span><span style="color:#F97583;">+</span><span style="color:#E1E4E8;"> age </span><span style="color:#F97583;">+</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'is running.'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> }</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> name,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> age,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> run</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> }</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">})()</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6A737D;">// moduleB.js</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(moduleA.name) </span><span style="color:#6A737D;">// 在其他模块中调用</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// moduleA.js</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">moduleA</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> (</span><span style="color:#D73A49;">function</span><span style="color:#24292E;">(){</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">name</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">"Ziu"</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">age</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">18</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">run</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> () </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(name </span><span style="color:#D73A49;">+</span><span style="color:#24292E;"> age </span><span style="color:#D73A49;">+</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'is running.'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;"> }</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> name,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> age,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> run</span></span>
|
||
<span class="line"><span style="color:#24292E;"> }</span></span>
|
||
<span class="line"><span style="color:#24292E;">})()</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6A737D;">// moduleB.js</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(moduleA.name) </span><span style="color:#6A737D;">// 在其他模块中调用</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><h3 id="commonjs" tabindex="-1">CommonJS <a class="header-anchor" href="#commonjs" aria-label="Permalink to "CommonJS""></a></h3><p>CommonJS是一种<strong>规范</strong>,当初命名为ServerJS,旨在浏览器以外的地方使用,后为体现其广泛性,改名为CommonJS,简称CJS</p><p><strong>规范 是用来指导 实现的</strong></p><ul><li><code>Node</code> 是CommonJS在服务端的代表<strong>实现</strong></li><li><code>Browserify</code> 是CommonJS在浏览器中的一种<strong>实现</strong> (正在被淘汰)</li><li><code>WebPack</code> 打包工具具备支持CommonJS的支持和转换</li></ul><p>所以,Node.js对CommonJS进行了支持和实现,让JavaScript在Node上运行时可以实现模块化开发</p><ul><li>每个<code>.js</code>文件都是一个单独的模块</li><li>每个模块中都包含变量<code>exports</code> <code>module.exports</code> <code>require</code></li></ul><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-t2cKi" id="tab-Xmu0NLl" checked="checked"><label for="tab-Xmu0NLl">env.js</label><input type="radio" name="group-t2cKi" id="tab-8wKjEZa"><label for="tab-8wKjEZa">utils.js</label><input type="radio" name="group-t2cKi" id="tab-NUYf0eH"><label for="tab-NUYf0eH">index.js</label></div><div class="blocks"><div class="language-js vp-adaptive-theme active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// env.js</span></span>
|
||
<span class="line"><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;">.name </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'Ziu'</span></span>
|
||
<span class="line"><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;">.age </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">18</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// env.js</span></span>
|
||
<span class="line"><span style="color:#005CC5;">exports</span><span style="color:#24292E;">.name </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'Ziu'</span></span>
|
||
<span class="line"><span style="color:#005CC5;">exports</span><span style="color:#24292E;">.age </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">18</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// utils.js</span></span>
|
||
<span class="line"><span style="color:#79B8FF;">module</span><span style="color:#E1E4E8;">.</span><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">sum</span><span style="color:#E1E4E8;">: </span><span style="color:#F97583;">function</span><span style="color:#E1E4E8;">(</span><span style="color:#FFAB70;">x</span><span style="color:#E1E4E8;">, </span><span style="color:#FFAB70;">y</span><span style="color:#E1E4E8;">) {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> x </span><span style="color:#F97583;">+</span><span style="color:#E1E4E8;"> y</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> }</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// utils.js</span></span>
|
||
<span class="line"><span style="color:#005CC5;">module</span><span style="color:#24292E;">.</span><span style="color:#005CC5;">exports</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#6F42C1;">sum</span><span style="color:#24292E;">: </span><span style="color:#D73A49;">function</span><span style="color:#24292E;">(</span><span style="color:#E36209;">x</span><span style="color:#24292E;">, </span><span style="color:#E36209;">y</span><span style="color:#24292E;">) {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> x </span><span style="color:#D73A49;">+</span><span style="color:#24292E;"> y</span></span>
|
||
<span class="line"><span style="color:#24292E;"> }</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// index.js</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">utils</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">require</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'utils.js'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">utils.</span><span style="color:#B392F0;">sum</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">1</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">) </span><span style="color:#6A737D;">// 3</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> { </span><span style="color:#79B8FF;">sum</span><span style="color:#E1E4E8;"> } </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">require</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'utils.js'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#B392F0;">sum</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">1</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">) </span><span style="color:#6A737D;">// 3</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> { </span><span style="color:#79B8FF;">name</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">age</span><span style="color:#E1E4E8;"> } </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">require</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'env.js'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(name, age) </span><span style="color:#6A737D;">// Ziu 18</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// index.js</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">utils</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">require</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'utils.js'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">utils.</span><span style="color:#6F42C1;">sum</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">1</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">2</span><span style="color:#24292E;">) </span><span style="color:#6A737D;">// 3</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> { </span><span style="color:#005CC5;">sum</span><span style="color:#24292E;"> } </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">require</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'utils.js'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">sum</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">1</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">2</span><span style="color:#24292E;">) </span><span style="color:#6A737D;">// 3</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> { </span><span style="color:#005CC5;">name</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">age</span><span style="color:#24292E;"> } </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">require</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'env.js'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(name, age) </span><span style="color:#6A737D;">// Ziu 18</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div></div></div><h4 id="exports的本质" tabindex="-1"><code>exports</code>的本质 <a class="header-anchor" href="#exports的本质" aria-label="Permalink to "\`exports\`的本质""></a></h4><p><code>exports</code>和<code>require</code>在Node中的本质</p><ul><li><code>exports</code>是一个对象,我们可以在这个对象中添加很多属性,添加的属性则会被导出 <ul><li>在没有向该对象添加任何属性之前,它是一个空对象</li></ul></li><li>当通过<code>require</code>导入时:<code>const env = require('env.js')</code><ul><li><code>env</code>这个变量等于<code>env.js</code>中的<code>exports</code>对象</li><li>本质上是<code>env</code>是<code>exports</code>对象的引用赋值</li><li><code>{ id: '...', exports: { ... }, loaded: true, ... }</code></li></ul></li><li>后续即使再次执行<code>require</code>导入模块,模块中的代码也不会重新执行(<code>module.loaded</code>属性) <ul><li>当从模块中取值时,会从已经加载的<code>exports</code>对象缓存上取值</li></ul></li></ul><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-oHpkr" id="tab-cBgcERg" checked="checked"><label for="tab-cBgcERg">utils.js</label><input type="radio" name="group-oHpkr" id="tab-ad1Fl_C"><label for="tab-ad1Fl_C">index.js</label></div><div class="blocks"><div class="language-js vp-adaptive-theme active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// utils.js</span></span>
|
||
<span class="line"><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;">.a </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">0</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6A737D;">// 1s后修改a值</span></span>
|
||
<span class="line"><span style="color:#B392F0;">setTimeout</span><span style="color:#E1E4E8;">(() </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;">.a </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">1</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}, </span><span style="color:#79B8FF;">1000</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6A737D;">// 2s后检查a值</span></span>
|
||
<span class="line"><span style="color:#B392F0;">setTimeout</span><span style="color:#E1E4E8;">(() </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;">.a) </span><span style="color:#6A737D;">// 2</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}, </span><span style="color:#79B8FF;">2000</span><span style="color:#E1E4E8;">)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// utils.js</span></span>
|
||
<span class="line"><span style="color:#005CC5;">exports</span><span style="color:#24292E;">.a </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">0</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6A737D;">// 1s后修改a值</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">setTimeout</span><span style="color:#24292E;">(() </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">exports</span><span style="color:#24292E;">.a </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">1</span></span>
|
||
<span class="line"><span style="color:#24292E;">}, </span><span style="color:#005CC5;">1000</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6A737D;">// 2s后检查a值</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">setTimeout</span><span style="color:#24292E;">(() </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">exports</span><span style="color:#24292E;">.a) </span><span style="color:#6A737D;">// 2</span></span>
|
||
<span class="line"><span style="color:#24292E;">}, </span><span style="color:#005CC5;">2000</span><span style="color:#24292E;">)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// index.js</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">utils</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">require</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'./utils'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(utils.a) </span><span style="color:#6A737D;">// 0</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#B392F0;">setTimeout</span><span style="color:#E1E4E8;">(() </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(utils.a) </span><span style="color:#6A737D;">// 1</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> utils.a </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;">// 反过来修改a值</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}, </span><span style="color:#79B8FF;">1500</span><span style="color:#E1E4E8;">)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// index.js</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">utils</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">require</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'./utils'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(utils.a) </span><span style="color:#6A737D;">// 0</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6F42C1;">setTimeout</span><span style="color:#24292E;">(() </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(utils.a) </span><span style="color:#6A737D;">// 1</span></span>
|
||
<span class="line"><span style="color:#24292E;"> utils.a </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">2</span><span style="color:#24292E;"> </span><span style="color:#6A737D;">// 反过来修改a值</span></span>
|
||
<span class="line"><span style="color:#24292E;">}, </span><span style="color:#005CC5;">1500</span><span style="color:#24292E;">)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div></div></div><p>在上述代码中,<code>utils</code>对象中的属性<code>a</code>在一秒后被赋值为<code>1</code>,因此在index.js中输出<code>utils.a</code>得到了两次不同的结果</p><p>反过来,在index.js中修改导入的<code>utils.a</code>的值后,修改结果也会反映在<code>exports.a</code>上,输出的值为<code>2</code></p><p>实际开发中不要修改导入模块中的变量,改变原模块中变量的值并不规范</p><h4 id="module-exports" tabindex="-1"><code>module.exports</code> <a class="header-anchor" href="#module-exports" aria-label="Permalink to "\`module.exports\`""></a></h4><p>在Node.js中,真正常用的导出方式是<code>module.exports</code></p><ul><li><code>module.exports</code>本质上就是<code>exports</code>对象(同一个内存地址)</li><li>可以直接给<code>exports</code>对象赋值,将需要导出的内容统一导出</li><li>给<code>module.exports</code>重新赋值,即改变了<code>exports</code>对象的指向,<strong>后续的修改不再影响原模块中的变量</strong></li></ul><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">name</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'Ziu'</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">run</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> () </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(name </span><span style="color:#F97583;">+</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'is running.'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#79B8FF;">module</span><span style="color:#E1E4E8;">.</span><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> name,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> run</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">name</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'Ziu'</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">run</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> () </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(name </span><span style="color:#D73A49;">+</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'is running.'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#005CC5;">module</span><span style="color:#24292E;">.</span><span style="color:#005CC5;">exports</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> name,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> run</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h4 id="二者的区别" tabindex="-1">二者的区别 <a class="header-anchor" href="#二者的区别" aria-label="Permalink to "二者的区别""></a></h4><p>既然如此,为什么还要存在<code>exports</code>这个概念呢?</p><ul><li>在CommonJS中是没有<code>module.exports</code>的概念的</li><li>为了实现模块的导出,Node.js使用的是<code>Module</code>类,每一个模块都是<code>Module</code>的实例,也就是<code>module</code></li><li>所以在Node.js中真正用于导出的并不是<code>exports</code>,而是<code>module.exports</code></li><li><code>module</code>对象中的<code>exports</code>属性是<code>exports</code>对象的一个引用 <ul><li><code>module.exports === exports === utils</code></li></ul></li></ul><p>如果<code>module.exports</code>不再引用<code>exports</code>对象了,修改<code>exports</code>对象也就没有意义了</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-FL0LG" id="tab-7E49s9k" checked="checked"><label for="tab-7E49s9k">utils.js</label><input type="radio" name="group-FL0LG" id="tab-3QONuOA"><label for="tab-3QONuOA">index.js</label></div><div class="blocks"><div class="language-js vp-adaptive-theme active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// utils.js</span></span>
|
||
<span class="line"><span style="color:#79B8FF;">module</span><span style="color:#E1E4E8;">.</span><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> name: </span><span style="color:#9ECBFF;">'Ziu'</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span>
|
||
<span class="line"><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;">.age </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">18</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// utils.js</span></span>
|
||
<span class="line"><span style="color:#005CC5;">module</span><span style="color:#24292E;">.</span><span style="color:#005CC5;">exports</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> name: </span><span style="color:#032F62;">'Ziu'</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span>
|
||
<span class="line"><span style="color:#005CC5;">exports</span><span style="color:#24292E;">.age </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">18</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// index.js</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">utils</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">require</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'utils.js'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(utils.name) </span><span style="color:#6A737D;">// Ziu</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(utils.age) </span><span style="color:#6A737D;">// undefined</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// index.js</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">utils</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">require</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'utils.js'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(utils.name) </span><span style="color:#6A737D;">// Ziu</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(utils.age) </span><span style="color:#6A737D;">// undefined</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div></div></div><p>当使用<code>module.exports = { ... }</code>后,模块中原有的<code>exports</code>不再被导入识别,导入的内容将变为<code>module.exports</code>指定的对象内容</p><h4 id="require的本质" tabindex="-1"><code>require</code>的本质 <a class="header-anchor" href="#require的本质" aria-label="Permalink to "\`require\`的本质""></a></h4><p><code>require</code>是一个函数,可以帮助我们导入一个文件(模块)中导出的对象</p><ul><li>为什么可以省略掉<code>.js</code>后缀,直接使用<code>require('./utils')</code></li><li>为什么可以省略掉<code>index.js</code>,直接使用<code>require('./tools')</code>导入<code>tools/index.js</code></li></ul><p>这涉及到<code>require</code>在匹配路径后的查找规则:</p><p>分为三种情况:<strong>内置模块、自定义路径、包名</strong></p><ul><li>导入Node.js内置的模块,如<code>const path = require('path')</code><ul><li>直接返回该内置模块 并停止后续的查找</li></ul></li><li>根据路径导入自定义的模块,如<code>const utils = require('./{filename}')</code><ul><li>按照路径寻找该模块<code>./</code> <code>../</code> <code>/</code></li><li>如果指定了后缀名,则按照后缀名查找</li><li>如果未指定后缀名,则: <ol><li>直接查找该文件</li><li>查找<code>{filename}.js</code>文件</li><li>查找<code>{filename}.json</code>文件</li><li>查找<code>{filename}.node</code>文件</li></ol></li><li>如果按照上述方式没找到文件,则<strong>将<code>{filename}</code>作为路径继续查找</strong></li><li>查找目录下的<code>index</code>文件 <code>{filename}/index</code><ol><li>查找<code>{filename}/index.js</code>文件</li><li>··· ···</li></ol></li><li>没找到:报错<code>Cannot find module 'xxx'</code></li></ul></li><li>包名,如<code>const lodash = require('lodash')</code><ul><li>到项目根目录的<code>node_modules</code>中查找</li><li><code>node_modules/{package_name}/index.js</code></li><li>当前项目目录的<code>node_modules</code>找不到则继续向上查找,直到查找到根目录的<code>node_modules</code></li></ul></li></ul><h4 id="模块的加载过程" tabindex="-1">模块的加载过程 <a class="header-anchor" href="#模块的加载过程" aria-label="Permalink to "模块的加载过程""></a></h4><ul><li>模块在被第一次引入时,模块中的JS代码会被运行一次 <ul><li>代码执行顺序与<code>require</code>的位置相关</li></ul></li><li>模块如果被多次引入,会被缓存,最终只加载一次 <ul><li>这是因为每个模块对象<code>module</code>上都有一个属性<code>loaded</code></li><li><code>loaded === false</code>表示该模块尚未被加载</li><li>第二次被<code>require</code>引入时会检查该属性是否为<code>true</code></li></ul></li><li>如果有循环引用,加载顺序如何? <ul><li>数据结构:图结构(graph)遍历时有深度优先搜索(DFS)、广度优先搜索(BFS)两种算法</li><li>Node采用的是深度优先算法</li></ul></li></ul><h4 id="commonjs的缺点" tabindex="-1">CommonJS的缺点 <a class="header-anchor" href="#commonjs的缺点" aria-label="Permalink to "CommonJS的缺点""></a></h4><ul><li>加载模块是同步加载的 <ul><li>只有等到对应的模块加载完毕,当前模块中的内容才能被执行</li><li>当然,在服务器中加载JS文件都是本地文件,加载速度非常快,不会受影响</li></ul></li><li>但是在浏览器中使用CommonJS <ul><li>需要先从服务器下载JS文件,后加载运行</li><li>阻塞JS执行 阻塞页面加载</li></ul></li><li>在WebPack中使用CommonJS <ul><li>CommonJS会被WebPack解析</li><li>将CommonJS代码转化为bundle 浏览器可以直接运行</li></ul></li></ul><h3 id="esmodule" tabindex="-1">ESModule <a class="header-anchor" href="#esmodule" aria-label="Permalink to "ESModule""></a></h3><ul><li>ES6 模块采用<strong>编译时加载</strong>,使得<strong>编译时就能确定模块的依赖关系</strong>,有助于<strong>静态优化</strong></li><li>CommonJS模块在运行时加载,且必须借助对象加载模块内容</li></ul><h4 id="export和import用法概览" tabindex="-1"><code>export</code>和<code>import</code>用法概览 <a class="header-anchor" href="#export和import用法概览" aria-label="Permalink to "\`export\`和\`import\`用法概览""></a></h4><p>ESModule借助<code>export</code>和<code>import</code>导入导出内容,需要注意的是导入导出的并不是对象</p><p><code>export</code>定义的是当前模块导出的<strong>接口</strong>,<code>import</code>可以导入来自其他不同模块的<strong>接口</strong></p><ul><li><code>export default</code>可以设置默认导出对象</li><li><code>export { ... }</code>可以统一导出多个内容</li><li><code>export</code>和<code>import</code>都可以使用<code>as</code>关键字重命名导出/导入的接口</li><li><code>import * from 'xxx'</code> <code>export * from 'xxx'</code>批量导入/导出</li></ul><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-9Fy9P" id="tab-e1hPAU6" checked="checked"><label for="tab-e1hPAU6">utils.js</label><input type="radio" name="group-9Fy9P" id="tab-2Fa_RhV"><label for="tab-2Fa_RhV">index.js</label></div><div class="blocks"><div class="language-js vp-adaptive-theme active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// utils.js</span></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">function</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">sum</span><span style="color:#E1E4E8;">(</span><span style="color:#FFAB70;">a</span><span style="color:#E1E4E8;">, </span><span style="color:#FFAB70;">b</span><span style="color:#E1E4E8;">) {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> a </span><span style="color:#F97583;">+</span><span style="color:#E1E4E8;"> b</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">function</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">sub</span><span style="color:#E1E4E8;">(</span><span style="color:#FFAB70;">a</span><span style="color:#E1E4E8;">, </span><span style="color:#FFAB70;">b</span><span style="color:#E1E4E8;">) {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> a </span><span style="color:#F97583;">-</span><span style="color:#E1E4E8;"> b</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">default</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">function</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#F97583;">...</span><span style="color:#FFAB70;">args</span><span style="color:#E1E4E8;">) {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;">args)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> name: 'Ziu',</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> age: 18</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">ENV_VARIABLE</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'Hello, World!'</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// utils.js</span></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">function</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">sum</span><span style="color:#24292E;">(</span><span style="color:#E36209;">a</span><span style="color:#24292E;">, </span><span style="color:#E36209;">b</span><span style="color:#24292E;">) {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> a </span><span style="color:#D73A49;">+</span><span style="color:#24292E;"> b</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">function</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">sub</span><span style="color:#24292E;">(</span><span style="color:#E36209;">a</span><span style="color:#24292E;">, </span><span style="color:#E36209;">b</span><span style="color:#24292E;">) {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> a </span><span style="color:#D73A49;">-</span><span style="color:#24292E;"> b</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">default</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">function</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#D73A49;">...</span><span style="color:#E36209;">args</span><span style="color:#24292E;">) {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#D73A49;">...</span><span style="color:#24292E;">args)</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> name: 'Ziu',</span></span>
|
||
<span class="line"><span style="color:#24292E;"> age: 18</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">ENV_VARIABLE</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'Hello, World!'</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// index.js</span></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> { sum, sub, name, age, ENV_VARIABLE } </span><span style="color:#F97583;">from</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'./utils'</span></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> log </span><span style="color:#F97583;">from</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'./utils.js'</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#B392F0;">sum</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">1</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">) </span><span style="color:#6A737D;">// 3</span></span>
|
||
<span class="line"><span style="color:#B392F0;">sub</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">3</span><span style="color:#E1E4E8;">) </span><span style="color:#6A737D;">// -1</span></span>
|
||
<span class="line"><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(name, age, </span><span style="color:#79B8FF;">ENV_VARIABLE</span><span style="color:#E1E4E8;">) </span><span style="color:#6A737D;">// 'Ziu' 18 'Hello, World!'</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// index.js</span></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> { sum, sub, name, age, ENV_VARIABLE } </span><span style="color:#D73A49;">from</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'./utils'</span></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> log </span><span style="color:#D73A49;">from</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'./utils.js'</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6F42C1;">sum</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">1</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">2</span><span style="color:#24292E;">) </span><span style="color:#6A737D;">// 3</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">sub</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">2</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">3</span><span style="color:#24292E;">) </span><span style="color:#6A737D;">// -1</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(name, age, </span><span style="color:#005CC5;">ENV_VARIABLE</span><span style="color:#24292E;">) </span><span style="color:#6A737D;">// 'Ziu' 18 'Hello, World!'</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div></div></div><p>需要注意的是,在浏览器中要使用ESModule,需要为<code><script></code>标签添加<code>module</code>标记:</p><p><code><script src="index.js" type="module"></script></code></p><ul><li>当浏览器解析到<code>type="module"</code>的JS代码后,会<strong>分析模块中导入的ESModule模块</strong></li><li>每导入一个ESModule模块,<strong>浏览器都会发起一个HTTP请求去加载它</strong></li><li>在本地运行时加载不同协议头的文件会遇到跨域问题,需要开启本地Web服务器</li></ul><p>另外,<strong><code>export</code>与<code>import</code>必须位于模块的顶层</strong>,如果位于作用域内会报错,因为这就<strong>无法对代码进行静态分析优化了</strong></p><h4 id="export详解" tabindex="-1"><code>export</code>详解 <a class="header-anchor" href="#export详解" aria-label="Permalink to "\`export\`详解""></a></h4><p><code>export</code>有两种导出方式:</p><ul><li>命名导出 <code>export const name = 'Ziu'</code> <code>export { v1, v2 } export * from 'xxx'</code><ul><li>导出时需要指定名字</li><li>导入时也需要知道对应的名字</li></ul></li><li>默认导出 <code>export default AGE = 18</code><ul><li>在从其他位置导入时需要为此默认导出指定新的名字</li><li>给用户方便:不必阅读文档就可以加载模块</li></ul></li></ul><h4 id="值的动态绑定" tabindex="-1">值的动态绑定 <a class="header-anchor" href="#值的动态绑定" aria-label="Permalink to "值的动态绑定""></a></h4><ul><li>ESModule模块通过<code>export</code>语句输出的接口,与其对应的值是<strong>动态绑定关系</strong>,即通<strong>过该接口,可以取到模块内部实时的值</strong></li><li>CommonJS模块输出的是值的缓存,不存在动态更新</li></ul><p>我们援引之前介绍CJS时的案例,<strong>将后缀名改为<code>mjs</code>即可在Node中运行ESModule模块代码</strong></p><p>初始获得的<code>a</code>值为0,经过1s后,在<code>utils.mjs</code>中修改了a的值,这时导入<code>utils.mjs</code>模块的其他模块可以获取到<code>a</code>最新的值</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-gipI3" id="tab-LkzUwcj" checked="checked"><label for="tab-LkzUwcj">utils.mjs</label><input type="radio" name="group-gipI3" id="tab-ZXsHhgd"><label for="tab-ZXsHhgd">index.mjs</label></div><div class="blocks"><div class="language-js vp-adaptive-theme active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// utils.mjs</span></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">let</span><span style="color:#E1E4E8;"> a </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">0</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6A737D;">// 1s后修改a值</span></span>
|
||
<span class="line"><span style="color:#B392F0;">setTimeout</span><span style="color:#E1E4E8;">(() </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> a </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">1</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}, </span><span style="color:#79B8FF;">1000</span><span style="color:#E1E4E8;">)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// utils.mjs</span></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">let</span><span style="color:#24292E;"> a </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">0</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6A737D;">// 1s后修改a值</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">setTimeout</span><span style="color:#24292E;">(() </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> a </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">1</span></span>
|
||
<span class="line"><span style="color:#24292E;">}, </span><span style="color:#005CC5;">1000</span><span style="color:#24292E;">)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// index.mjs</span></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> { a } </span><span style="color:#F97583;">from</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'./utils.mjs'</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(a) </span><span style="color:#6A737D;">// 0</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#B392F0;">setTimeout</span><span style="color:#E1E4E8;">(() </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(a) </span><span style="color:#6A737D;">// 1</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}, </span><span style="color:#79B8FF;">1500</span><span style="color:#E1E4E8;">)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// index.mjs</span></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> { a } </span><span style="color:#D73A49;">from</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'./utils.mjs'</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(a) </span><span style="color:#6A737D;">// 0</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#6F42C1;">setTimeout</span><span style="color:#24292E;">(() </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(a) </span><span style="color:#6A737D;">// 1</span></span>
|
||
<span class="line"><span style="color:#24292E;">}, </span><span style="color:#005CC5;">1500</span><span style="color:#24292E;">)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div></div></div><ul><li>需要注意的是,导入的其他模块的变量是不允许被修改的,因为<code>index.mjs</code>导入的本质是一个接口</li><li>如果从其他模块导入的是一个对象,也不推荐修改导入内容的任何值,最好将其当做完全只读</li></ul><p>拓展阅读:CommonJS与ESModule加载模块的异同</p><h4 id="import详解" tabindex="-1"><code>import</code>详解 <a class="header-anchor" href="#import详解" aria-label="Permalink to "\`import\`详解""></a></h4><p>检查下述代码:</p><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">foo</span><span style="color:#E1E4E8;">()</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> { foo } </span><span style="color:#F97583;">from</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'foo'</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">foo</span><span style="color:#24292E;">()</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> { foo } </span><span style="color:#D73A49;">from</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'foo'</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><ul><li><code>import</code>命令具有提升效果,会提升到整个模块的顶部</li><li><code>import</code>的执行早于函数的调用,<code>import</code>命令是在编译阶段执行的,在代码运行之前</li><li>由于<code>import</code>是静态执行,所以不能使用表达式和变量(只有运行时才有值)</li></ul><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'lodash'</span></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'lodash'</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'lodash'</span></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'lodash'</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><ul><li>如果仅仅导入了一个模块,那么该模块的代码会被执行,但是没有任何变量被导入</li><li>如果同一模块被导入多次,那么导入操作只会被执行一次</li></ul><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">*</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">from</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'utils'</span></span>
|
||
<span class="line"><span style="color:#B392F0;">add</span><span style="color:#E1E4E8;">(</span><span style="color:#79B8FF;">1</span><span style="color:#E1E4E8;">, </span><span style="color:#79B8FF;">2</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">*</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">from</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'utils'</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">*</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">from</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'utils'</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">add</span><span style="color:#24292E;">(</span><span style="color:#005CC5;">1</span><span style="color:#24292E;">, </span><span style="color:#005CC5;">2</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">*</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">from</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'utils'</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><ul><li>可以通过<code>*</code>一次性导入模块中所有导出的变量、函数、类</li><li>也可以实现二者的复合操作:导入全部模块的同时导出全部模块</li></ul><h4 id="import-函数" tabindex="-1"><code>import()</code>函数 <a class="header-anchor" href="#import-函数" aria-label="Permalink to "\`import()\`函数""></a></h4><p>通过<code>import</code>命令导入的模块是静态的,会被提升到模块顶部,并不支持条件导入</p><p>ES2020引入了<code>import()</code>函数,可以通过<code>import()</code>函数实现条件导入,动态加载ESModule模块</p><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">main</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> document.</span><span style="color:#B392F0;">querySelector</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'main'</span><span style="color:#E1E4E8;">);</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">\`./section-modules/\${</span><span style="color:#E1E4E8;">someVariable</span><span style="color:#9ECBFF;">}.js\`</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> .</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">(</span><span style="color:#FFAB70;">module</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">module</span><span style="color:#E1E4E8;">.</span><span style="color:#B392F0;">loadPageInto</span><span style="color:#E1E4E8;">(main);</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> })</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> .</span><span style="color:#B392F0;">catch</span><span style="color:#E1E4E8;">(</span><span style="color:#FFAB70;">err</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> main.textContent </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> err.message;</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> })</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">main</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> document.</span><span style="color:#6F42C1;">querySelector</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'main'</span><span style="color:#24292E;">);</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;">(</span><span style="color:#032F62;">\`./section-modules/\${</span><span style="color:#24292E;">someVariable</span><span style="color:#032F62;">}.js\`</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;"> .</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">(</span><span style="color:#E36209;">module</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">module</span><span style="color:#24292E;">.</span><span style="color:#6F42C1;">loadPageInto</span><span style="color:#24292E;">(main);</span></span>
|
||
<span class="line"><span style="color:#24292E;"> })</span></span>
|
||
<span class="line"><span style="color:#24292E;"> .</span><span style="color:#6F42C1;">catch</span><span style="color:#24292E;">(</span><span style="color:#E36209;">err</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> main.textContent </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> err.message;</span></span>
|
||
<span class="line"><span style="color:#24292E;"> })</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><ul><li>返回值是一个Promise对象,可以通过<code>await</code>同步地操作它</li><li><code>import()</code>函数可以在模块外的JS脚本中使用,用于<strong>在运行时加载外部模块</strong>,类似于<code>require()</code></li><li>区别于<code>require()</code>,<code>import()</code>是异步加载模块</li></ul><p>通过<code>.then</code>函数处理导入的模块时,行为和<code>import</code>是相同的:</p><ul><li>如果有默认导出对象,则<code>.then</code>入参为默认导出对象</li><li>可以通过解构直接取到模块中导出的变量或函数:<code>.then(({ add, sub }) => { ... })</code></li></ul><p><strong>应用场景</strong></p><p>按需加载:按钮点击后才加载相关的JS文件</p><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#E1E4E8;">btn.</span><span style="color:#B392F0;">addEventListener</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'click'</span><span style="color:#E1E4E8;">, () </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">import</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'./dialogBox.js'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> .</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">(</span><span style="color:#FFAB70;">dialogBox</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> dialogBox.</span><span style="color:#B392F0;">open</span><span style="color:#E1E4E8;">()</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> })</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> .</span><span style="color:#B392F0;">catch</span><span style="color:#E1E4E8;">(</span><span style="color:#FFAB70;">err</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(err))</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">})</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292E;">btn.</span><span style="color:#6F42C1;">addEventListener</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'click'</span><span style="color:#24292E;">, () </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">import</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'./dialogBox.js'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;"> .</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">(</span><span style="color:#E36209;">dialogBox</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> dialogBox.</span><span style="color:#6F42C1;">open</span><span style="color:#24292E;">()</span></span>
|
||
<span class="line"><span style="color:#24292E;"> })</span></span>
|
||
<span class="line"><span style="color:#24292E;"> .</span><span style="color:#6F42C1;">catch</span><span style="color:#24292E;">(</span><span style="color:#E36209;">err</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(err))</span></span>
|
||
<span class="line"><span style="color:#24292E;">})</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>条件加载:根据主题色加载不同JS文件</p><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">if</span><span style="color:#E1E4E8;">(darkMode) {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">import</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'dark.js'</span><span style="color:#E1E4E8;">).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">(() </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">} </span><span style="color:#F97583;">else</span><span style="color:#E1E4E8;"> {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">import</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'light.js'</span><span style="color:#E1E4E8;">).</span><span style="color:#B392F0;">then</span><span style="color:#E1E4E8;">(() </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">...</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">if</span><span style="color:#24292E;">(darkMode) {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">import</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'dark.js'</span><span style="color:#24292E;">).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">(() </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> </span><span style="color:#D73A49;">...</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">} </span><span style="color:#D73A49;">else</span><span style="color:#24292E;"> {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">import</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'light.js'</span><span style="color:#24292E;">).</span><span style="color:#6F42C1;">then</span><span style="color:#24292E;">(() </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> </span><span style="color:#D73A49;">...</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>传入动态值</p><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">let</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">moduleName</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> () </span><span style="color:#F97583;">=></span><span style="color:#E1E4E8;"> [</span><span style="color:#9ECBFF;">'Home'</span><span style="color:#E1E4E8;">, </span><span style="color:#9ECBFF;">'History'</span><span style="color:#E1E4E8;">, </span><span style="color:#9ECBFF;">'User'</span><span style="color:#E1E4E8;">][</span><span style="color:#79B8FF;">0</span><span style="color:#E1E4E8;">]</span></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">\`./\${</span><span style="color:#B392F0;">moduleName</span><span style="color:#9ECBFF;">()</span><span style="color:#9ECBFF;">}.js\`</span><span style="color:#E1E4E8;">)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">let</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">moduleName</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> () </span><span style="color:#D73A49;">=></span><span style="color:#24292E;"> [</span><span style="color:#032F62;">'Home'</span><span style="color:#24292E;">, </span><span style="color:#032F62;">'History'</span><span style="color:#24292E;">, </span><span style="color:#032F62;">'User'</span><span style="color:#24292E;">][</span><span style="color:#005CC5;">0</span><span style="color:#24292E;">]</span></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;">(</span><span style="color:#032F62;">\`./\${</span><span style="color:#6F42C1;">moduleName</span><span style="color:#032F62;">()</span><span style="color:#032F62;">}.js\`</span><span style="color:#24292E;">)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h4 id="import-meta" tabindex="-1"><code>i<wbr>mport.meta</code> <a class="header-anchor" href="#import-meta" aria-label="Permalink to "\`i<wbr>mport.meta\`""></a></h4><p>ES2020引入了<code>i<wbr>mport.meta</code>,它仅能在模块内部使用,包含一些模块自身的信息,即模块元信息</p><ul><li><code>i<wbr>mport.meta.url</code> 返回当前模块的URL路径 <ul><li>浏览器加载ESModule都是通过HTTP发起请求 <ul><li>例如当前模块为<code>fetchData.js</code>,要在模块内引入一个名为<code>data.json</code>的数据:</li><li><code>import( new URL('data.json', i<wbr>mport.meta.url) )</code></li></ul></li><li>Node.js环境下,该值都是<code>file://</code>协议的链接</li></ul></li><li><code>i<wbr>mport.meta.scriptElement</code><ul><li>浏览器特有的属性</li><li>返回加载模块的<code><script></code>标签,相当于<code>document.currentScript</code></li></ul></li></ul><p>规范中并未规定<code>i<wbr>mport.meta</code>中包含哪些属性,一般包括上面两个属性</p><h3 id="深入理解模块加载" tabindex="-1">深入理解模块加载 <a class="header-anchor" href="#深入理解模块加载" aria-label="Permalink to "深入理解模块加载""></a></h3><h4 id="esmodule的解析过程" tabindex="-1">ESModule的解析过程 <a class="header-anchor" href="#esmodule的解析过程" aria-label="Permalink to "ESModule的解析过程""></a></h4><p>ESModule的解析过程可以分为三个阶段:</p><ul><li>构建 <code>Construction</code><ul><li>根据地址查找JS文件,并发起HTTP请求下载,将其解析为模块记录 <code>Module Record</code></li></ul></li><li>实例化 <code>Instatiation</code><ul><li>对模块记录进行实例化,并为其分配内存空间</li><li>解析ESModule模块的<strong>导入和导出</strong>语句,将模块指向对应的内存地址</li><li>例如<code>export const name = 'Ziu'</code>,会将变量<code>name</code>添加到模块环境记录中 <code>Module Enviroment Record</code></li></ul></li><li>运行 <code>Evaluation</code><ul><li>运行代码,计算值,并且将值填充到内存地址中</li><li>将导入导出的<strong>值</strong>赋给对应的变量<code>name = 'Ziu'</code></li></ul></li></ul><p><img src="`+p+`" alt="ESModule解析过程"></p><p>文章推荐:<a href="https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/" target="_blank" rel="noreferrer">ES modules: A cartoon deep-dive</a></p><h4 id="mjs和cjs的区别" tabindex="-1">MJS和CJS的区别 <a class="header-anchor" href="#mjs和cjs的区别" aria-label="Permalink to "MJS和CJS的区别""></a></h4><ul><li><strong>CommonJS模块输出的是值的拷贝,而ESModule模块输出的是值的引用</strong><ul><li>CJS导出的变量,其值如果在模块内发生变化,外部导入是不会同步更新的,除非导出的是一个取值函数</li><li>MJS导出变量,外部模块每次访问时都会得到该变量最新的值,即使变量在模块内被修改了</li></ul></li><li><strong>CommonJS模块是运行时加载,而ESModule是编译时输出接口</strong><ul><li>CJS是<strong>通过对象实现</strong>的导入导出,它<strong>在运行时才被确定依赖关系</strong>和其值</li><li>MJS则是<strong>通过静态定义</strong>,在代码运行之前的<strong>静态解析阶段即可确定模块的导入导出内容</strong></li></ul></li><li><strong>CommonJS模块的<code>require()</code>是同步加载模块,而ESModule模块的<code>import</code>命令是异步加载模块</strong><ul><li><code>import</code>命令拥有一个独立的模块依赖的解析阶段</li></ul></li></ul><h4 id="cjs中的循环加载" tabindex="-1">CJS中的循环加载 <a class="header-anchor" href="#cjs中的循环加载" aria-label="Permalink to "CJS中的循环加载""></a></h4><p>设想有以下两文件 <code>a.js</code>与<code>b.js</code>:</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-CBvze" id="tab-PKCtbqD" checked="checked"><label for="tab-PKCtbqD">a.js</label><input type="radio" name="group-CBvze" id="tab-vdc778c"><label for="tab-vdc778c">b.js</label><input type="radio" name="group-CBvze" id="tab-llzkh20"><label for="tab-llzkh20">main.js</label></div><div class="blocks"><div class="language-js vp-adaptive-theme active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// a.js</span></span>
|
||
<span class="line"><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;">.done </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">false</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">b</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">require</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'./b.js'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'在 a.js 之中,b.done = %j'</span><span style="color:#E1E4E8;">, b.done)</span></span>
|
||
<span class="line"><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;">.done </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">true</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'a.js 执行完毕'</span><span style="color:#E1E4E8;">)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// a.js</span></span>
|
||
<span class="line"><span style="color:#005CC5;">exports</span><span style="color:#24292E;">.done </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">false</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">b</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">require</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'./b.js'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'在 a.js 之中,b.done = %j'</span><span style="color:#24292E;">, b.done)</span></span>
|
||
<span class="line"><span style="color:#005CC5;">exports</span><span style="color:#24292E;">.done </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">true</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'a.js 执行完毕'</span><span style="color:#24292E;">)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// b.js</span></span>
|
||
<span class="line"><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;">.done </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">false</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">a</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">require</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'./a.js'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'在 b.js 之中,a.done = %j'</span><span style="color:#E1E4E8;">, a.done)</span></span>
|
||
<span class="line"><span style="color:#79B8FF;">exports</span><span style="color:#E1E4E8;">.done </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">true</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'b.js 执行完毕'</span><span style="color:#E1E4E8;">)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// b.js</span></span>
|
||
<span class="line"><span style="color:#005CC5;">exports</span><span style="color:#24292E;">.done </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">false</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">a</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">require</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'./a.js'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'在 b.js 之中,a.done = %j'</span><span style="color:#24292E;">, a.done)</span></span>
|
||
<span class="line"><span style="color:#005CC5;">exports</span><span style="color:#24292E;">.done </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">true</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'b.js 执行完毕'</span><span style="color:#24292E;">)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// main.js</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">a</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">require</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'./a'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">b</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">require</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'./b'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'在 main.js 之中, a.done=%j, b.done=%j'</span><span style="color:#E1E4E8;">, a.done, b.done)</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// main.js</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">a</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">require</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'./a'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">b</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">require</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'./b'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'在 main.js 之中, a.done=%j, b.done=%j'</span><span style="color:#24292E;">, a.done, b.done)</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div></div></div><p>执行脚本<code>main.js</code>,先执行<code>a.js</code>:</p><ul><li>第一行 导出<code>done</code>值为<code>false</code></li><li>第二行 <code>a.js</code>的代码暂停执行 进入<code>b.js</code>并等待其执行完毕</li></ul><p>在<code>b.js</code>中:</p><ul><li>第一行 导出<code>done</code>值为<code>false</code></li><li>第二行 执行<code>a.js</code> 从<code>a.js</code>模块中取<code>exports</code>对象</li><li><strong>取到其缓存值为<code>false</code>(<code>a.js</code>执行已经执行的部分)</strong></li><li>随后<code>b.js</code>继续向下执行 执行完毕后 将执行权交还给<code>a.js</code></li></ul><p>回到<code>a.js</code>中:</p><ul><li>继续向后执行 直到代码执行完毕</li></ul><p>最终输出:</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">在</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">b.js</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">之中,a.done</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">false</span></span>
|
||
<span class="line"><span style="color:#B392F0;">b.js</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">执行完毕</span></span>
|
||
<span class="line"><span style="color:#B392F0;">在</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">a.js</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">之中,b.done</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">true</span></span>
|
||
<span class="line"><span style="color:#B392F0;">a.js</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">执行完毕</span></span>
|
||
<span class="line"><span style="color:#B392F0;">在</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">main.js</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">之中,</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">a.done=</span><span style="color:#79B8FF;">true</span><span style="color:#9ECBFF;">,</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">b.done=</span><span style="color:#79B8FF;">true</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">在</span><span style="color:#24292E;"> </span><span style="color:#032F62;">b.js</span><span style="color:#24292E;"> </span><span style="color:#032F62;">之中,a.done</span><span style="color:#24292E;"> </span><span style="color:#032F62;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">false</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">b.js</span><span style="color:#24292E;"> </span><span style="color:#032F62;">执行完毕</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">在</span><span style="color:#24292E;"> </span><span style="color:#032F62;">a.js</span><span style="color:#24292E;"> </span><span style="color:#032F62;">之中,b.done</span><span style="color:#24292E;"> </span><span style="color:#032F62;">=</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">true</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">a.js</span><span style="color:#24292E;"> </span><span style="color:#032F62;">执行完毕</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">在</span><span style="color:#24292E;"> </span><span style="color:#032F62;">main.js</span><span style="color:#24292E;"> </span><span style="color:#032F62;">之中,</span><span style="color:#24292E;"> </span><span style="color:#032F62;">a.done=</span><span style="color:#005CC5;">true</span><span style="color:#032F62;">,</span><span style="color:#24292E;"> </span><span style="color:#032F62;">b.done=</span><span style="color:#005CC5;">true</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>总结:</p><ul><li>CJS的模块导出是输出值的拷贝,而不是引用,值的变化不是动态的,而是会被缓存的</li><li>循环加载时,CJS模块导出的值是当前已经执行部分代码产生的结果的值,而不是模块代码完全执行完后的最终值</li></ul><h4 id="mjs中的循环加载" tabindex="-1">MJS中的循环加载 <a class="header-anchor" href="#mjs中的循环加载" aria-label="Permalink to "MJS中的循环加载""></a></h4><p>ESModule的导入和导出与CommonJS有本质不同:</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-wot6D" id="tab-Q1NjOx5" checked="checked"><label for="tab-Q1NjOx5">a.mjs</label><input type="radio" name="group-wot6D" id="tab-7ADSeme"><label for="tab-7ADSeme">b.mjs</label></div><div class="blocks"><div class="language-js vp-adaptive-theme active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// a.mjs</span></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> { bar } </span><span style="color:#F97583;">from</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'./b.mjs'</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'a.mjs'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(bar)</span></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">let</span><span style="color:#E1E4E8;"> foo </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'foo'</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// a.mjs</span></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> { bar } </span><span style="color:#D73A49;">from</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'./b.mjs'</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'a.mjs'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(bar)</span></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">let</span><span style="color:#24292E;"> foo </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'foo'</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// b.mjs</span></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> { foo } </span><span style="color:#F97583;">from</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'./a.mjs'</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'b.mjs'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(foo)</span></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">let</span><span style="color:#E1E4E8;"> bar </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'bar'</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// b.mjs</span></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> { foo } </span><span style="color:#D73A49;">from</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'./a.mjs'</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'b.mjs'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(foo)</span></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">let</span><span style="color:#24292E;"> bar </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'bar'</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div></div></div><p>执行<code>a.mjs</code>后发现报错了:<code>ReferenceError: Cannot access 'foo' before initialization</code>,变量<code>foo</code>未定义</p><ul><li>MJS模块在代码执行前会进行静态分析</li><li>分析<code>a.mjs</code>的依赖关系时,发现其依赖了<code>b.mjs</code></li><li>于是加载<code>b.mjs</code>并解析它的依赖关系</li><li>解析<code>b.mjs</code>的过程中,发现它又依赖了<code>a.mjs</code></li><li>这时引擎不会再去加载<code>a.mjs</code> 而是认为<code>a.mjs</code>这个模块的<code>Module Record</code>已经存在了</li><li>继续向下执行,执行到<code>console.log(foo)</code>时发现<code>foo</code>未定义 抛出错误</li></ul><p>要实现预期效果,可以将<code>foo</code>与<code>bar</code>改写为取值函数,这时执行就不会报错了:</p><div class="vp-code-group vp-adaptive-theme"><div class="tabs"><input type="radio" name="group-igQ1G" id="tab-Px4KDGV" checked="checked"><label for="tab-Px4KDGV">a.mjs</label><input type="radio" name="group-igQ1G" id="tab-Y_WHg5y"><label for="tab-Y_WHg5y">b.mjs</label></div><div class="blocks"><div class="language-js vp-adaptive-theme active line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// a.mjs</span></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> { bar } </span><span style="color:#F97583;">from</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'./b.mjs'</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'a.mjs'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#B392F0;">bar</span><span style="color:#E1E4E8;">())</span></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">function</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">foo</span><span style="color:#E1E4E8;">() {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'foo'</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// a.mjs</span></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> { bar } </span><span style="color:#D73A49;">from</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'./b.mjs'</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'a.mjs'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#6F42C1;">bar</span><span style="color:#24292E;">())</span></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">function</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">foo</span><span style="color:#24292E;">() {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'foo'</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#6A737D;">// b.mjs</span></span>
|
||
<span class="line"><span style="color:#F97583;">import</span><span style="color:#E1E4E8;"> { foo } </span><span style="color:#F97583;">from</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'./a.mjs'</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'b.mjs'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(</span><span style="color:#B392F0;">foo</span><span style="color:#E1E4E8;">())</span></span>
|
||
<span class="line"><span style="color:#F97583;">export</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">function</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">bar</span><span style="color:#E1E4E8;">() {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">return</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'bar'</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6A737D;">// b.mjs</span></span>
|
||
<span class="line"><span style="color:#D73A49;">import</span><span style="color:#24292E;"> { foo } </span><span style="color:#D73A49;">from</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'./a.mjs'</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'b.mjs'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(</span><span style="color:#6F42C1;">foo</span><span style="color:#24292E;">())</span></span>
|
||
<span class="line"><span style="color:#D73A49;">export</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">function</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">bar</span><span style="color:#24292E;">() {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#D73A49;">return</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'bar'</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div></div></div><p>这是因为函数<code>function</code>具有提升作用,在<code>a.mjs</code>中执行<code>import { bar } from './b.mjs'</code>之前,<code>foo</code>就有定义了。</p><p>因此在进入<code>b.mjs</code>执行<code>console.log(foo())</code>时可以取到<code>foo</code>,代码可以顺利执行</p><p>另:如果将<code>foo</code>定义为函数表达式<code>export const foo = () => 'foo'</code>,由于没有变量提升,代码仍然会报错</p><h4 id="内部变量差异" tabindex="-1">内部变量差异 <a class="header-anchor" href="#内部变量差异" aria-label="Permalink to "内部变量差异""></a></h4><p>ESModule和CommonJS另一个重要区别就是:</p><p>ESModule模块是在浏览器与服务端通用的,之前在解读CommonJS时介绍了它拥有的一些内部变量(模块变量):</p><ul><li><code>arguments</code></li><li><code>require</code></li><li><code>module</code></li><li><code>exports</code></li><li><code>__filename</code></li><li><code>_dirname</code></li></ul><p>这些变量在ESModule模块中都是不存在的,且顶层的<code>this</code>不再指向当前模块,而是<code>undefined</code></p><h3 id="拓展内容" tabindex="-1">拓展内容 <a class="header-anchor" href="#拓展内容" aria-label="Permalink to "拓展内容""></a></h3><h4 id="在node-js中使用esmodule" tabindex="-1">在Node.js中使用ESModule <a class="header-anchor" href="#在node-js中使用esmodule" aria-label="Permalink to "在Node.js中使用ESModule""></a></h4><p>在Node.js中,普通的<code>.js</code>文件会被默认解析为CommonJS,要使用ESModule有两种方式:</p><ul><li>所有ESModule的后缀名都使用<code>.mjs</code>并且不可省略 <ul><li>这样引擎在解析到<code>.mjs</code>结尾的文件时,将按照ESModule的规则解析其导入导出关系</li></ul></li><li>将<code>package.json</code>中的<code>type</code>字段修改为<code>module</code><ul><li>此时项目中所有<code>.js</code>文件都将被作为ESModule模块解析</li><li>要在此项目中使用CommonJS,则需要将后缀名修改为<code>.cjs</code></li></ul></li></ul><h4 id="解读package-json中的字段" tabindex="-1">解读<code>package.json</code>中的字段 <a class="header-anchor" href="#解读package-json中的字段" aria-label="Permalink to "解读\`package.json\`中的字段""></a></h4><ul><li></li></ul><h2 id="包管理工具" tabindex="-1">包管理工具 <a class="header-anchor" href="#包管理工具" aria-label="Permalink to "包管理工具""></a></h2><ul><li>npm包管理工具</li><li>package配置文件</li><li>npm install原理</li><li>yarn cnpm npx</li><li>发布自己的npm包</li><li>pnpm使用和原理</li></ul><h3 id="npm" tabindex="-1">npm <a class="header-anchor" href="#npm" aria-label="Permalink to "npm""></a></h3><ul><li>Node Package Manager 包管理工具,方便管理项目依赖、管理代码版本、分发代码</li><li>目前不仅管理Node的包了,前端项目的依赖包都可以由它管理</li><li>安装Node.js会自动为我们安装npm</li></ul><p>全局安装、局部安装、开发依赖、生产依赖</p><h3 id="package-json" tabindex="-1">package.json <a class="header-anchor" href="#package-json" aria-label="Permalink to "package.json""></a></h3><p><code>package.json</code>用来记录项目的配置信息,包括项目名、版本、项目入口、脚本、依赖项</p><p>通过<code>npm init -y</code>初始化项目,会为我们生成一个<code>package.json</code>文件</p><p>强烈建议阅读官方文档对<code>package.json</code>的解读:<a href="https://docs.npmjs.com/cli/v9/configuring-npm/package-json" target="_blank" rel="noreferrer">package.json</a></p><h4 id="main与exports字段" tabindex="-1"><code>main</code>与<code>exports</code>字段 <a class="header-anchor" href="#main与exports字段" aria-label="Permalink to "\`main\`与\`exports\`字段""></a></h4><ul><li><p><code>main</code>字段</p><ul><li>指定一个npm包的<code>main</code>字段为一个JS模块</li><li>当我们从其他位置通过<code>import { something } from 'es-module-package'</code>导入时</li><li>Node.js将从<code>main</code>字段指定的模块查找导出内容</li></ul></li><li><p><code>exports</code>字段</p><ul><li><code>exports</code>字段优先级高于<code>main</code>字段,它具有多种用法:</li><li>子目录别名 <ul><li>假设如是定义<code>exports</code>字段:<code>exports: { "./submodule": "./src/submodule.js" }</code></li><li>当执行<code>import submodule from 'es-module-package/submodule'</code>时,会按照以下路径查找模块:</li><li><code>./node_modules/es-module-package/src/submodule.js</code></li></ul></li><li><code>main</code>的别名</li><li>条件加载</li></ul></li></ul><p>参考:<a href="https://es6.ruanyifeng.com/#docs/module-loader#package-json-%E7%9A%84-exports-%E5%AD%97%E6%AE%B5" target="_blank" rel="noreferrer">package.json 的 exports 字段</a></p><h4 id="dependencies和devdependencies的区别" tabindex="-1"><code>dependencies</code>和<code>devDependencies</code>的区别 <a class="header-anchor" href="#dependencies和devdependencies的区别" aria-label="Permalink to "\`dependencies\`和\`devDependencies\`的区别""></a></h4><ul><li><code>dependencies</code>应当包含依赖的最小集,在此之上添加的文档、测试、调试、构建等的依赖,都应当被放进<code>devDependencies</code></li><li>当别人安装你发布的npm包时,执行<code>npm install xxx</code>后,只会安装包本身以及其中的<code>dependencies</code>运行时依赖</li><li>如果使用打包工具如Webpack,不论依赖放在哪一个里面,只要项目中有引入就会被打包进生产,除非配置了<code>external</code></li></ul><p>官方对两个字段的定义:</p><blockquote><p>dependencies: Dependencies are specified in a simple object that maps a package name to a version range. The version range is a string which has one or more space-separated descriptors. Dependencies can also be identified with a tarball or git URL.</p></blockquote><blockquote><p>devDependencies: If someone is planning on downloading and using your module in their program, then they probably don't want or need to download and build the external test or documentation framework that you use.</p></blockquote><p><strong>总结:将与代码运行时无关的依赖放入<code>devDependencies</code>,可以让他人在使用你开发的库时,少安装一些不必要的依赖。</strong></p><h4 id="依赖版本号中的-1-2-0和-1-2-0有什么区别" tabindex="-1">依赖版本号中的<code>~1.2.0</code>和<code>^1.2.0</code>有什么区别 <a class="header-anchor" href="#依赖版本号中的-1-2-0和-1-2-0有什么区别" aria-label="Permalink to "依赖版本号中的\`~1.2.0\`和\`^1.2.0\`有什么区别""></a></h4><p>版本号简要说明:<code>[major 主要版本].[minor 次要版本].[patch 补丁版本]-[alpha | beta 测试阶段].[测试版本号]</code></p><ul><li><p><code>~</code> Allows patch-level changes if a minor version is specified on the comparator. Allows minor-level changes if not.</p><ul><li>如果指定了次要版本,则允许补丁级别的更改,否则允许进行较小级别的更改</li><li>如<code>~1.2.0</code>:允许安装<code>1.2.0 - 1.3.0</code>的版本</li><li>如<code>~1.2</code>:允许安装<code>1.2.0 - 1.3.0</code>的版本</li><li>如<code>~1</code>:允许安装<code>1.x</code>的版本,不允许上升到<code>2.0.0</code></li></ul></li><li><p><code>^</code> Allows changes that do not modify the left-most non-zero element in the <code>[major, minor, patch]</code> tuple.</p></li><li><p>允许对<code>1.0.0</code>及更高版本进行补丁和次要更新,对版本<code>0.x >=0.1.0</code>进行补丁更新,对版本<code>0.0.x</code>不进行更新。</p><ul><li>如<code>^1.2.3</code>:允许安装<code>1.2.3 - 2.0.0</code>的版本</li><li>如<code>^0.2.3</code>:允许安装<code>0.2.3 - 0.3.0</code>的版本</li><li>如<code>^0.0.3</code>:允许安装<code>0.0.3 - 0.0.4</code>的版本</li></ul></li></ul><p>参考:<a href="https://github.com/npm/node-semver#versions" target="_blank" rel="noreferrer">node-semver</a></p><p>Allows patch-level changes if a minor version is specified on the comparator. Allows minor-level changes if not.</p><p>devDependenciesAllows changes that do not modify the left-most non-zero element in the [major, minor, patch] tuple.</p><p>允许对版本 1.0.0 及更高版本进行补丁和次要更新,对版本 0.X >=0.1.0 进行补丁更新,对版本 0.0.X 不进行更新。</p><h3 id="npx" tabindex="-1">npx <a class="header-anchor" href="#npx" aria-label="Permalink to "npx""></a></h3><p><code>npx</code>命令用来在项目路径下执行<code>node_modules/.bin</code>下的命令,默认这些命令都位于<code>node_modules/.bin</code>中,如果不cd进去shell找不到它们,在项目根目录调用它们自然会报未知命令的错误。</p><p>以webpack为例:</p><ul><li>直接在控制台输入<code>webpack</code>会报错:未知命令</li><li>必须通过<code>npx webpack</code>来替我们调用 <ul><li>这相当于在控制台执行了<code>./node_modules/.bin/webpack</code></li></ul></li><li>通过在<code>package.json</code>中定义<code>script</code><ul><li>执行<code>npm run xxx</code>后,会为我们将<code>.bin</code>中的命令添加进系统的PATH中</li><li>这样就相当于直接在项目根目录下直接调用<code>.bin</code>中的命令了</li></ul></li><li>如果全局安装了webpack那么在系统任意路径下都可以用<code>webpack</code>命令了</li></ul><h4 id="解读package-json中的bin字段" tabindex="-1">解读<code>package.json</code>中的<code>bin</code>字段 <a class="header-anchor" href="#解读package-json中的bin字段" aria-label="Permalink to "解读\`package.json\`中的\`bin\`字段""></a></h4><p><code>.bin</code>目录下的可执行文件从何处来?由npm官方文档中对<code>package.json/bin</code>字段的介绍可以知道:</p><blockquote><p>A lot of packages have one or more executable files that they'd like to install into the PATH. npm makes this pretty easy (in fact, it uses this feature to install the "npm" executable.)</p><p>To use this, supply a <code>bin</code> field in your package.json which is a map of command name to local file name. When this package is installed globally, that file will be either linked inside the global bins directory or a cmd (Windows Command File) will be created which executes the specified file in the <code>bin</code> field, so it is available to run by <code>name</code> or <code>name.cmd</code> (on Windows PowerShell). When this package is installed as a dependency in another package, the file will be linked where it will be available to that package either directly by <code>npm exec</code> or by name in other scripts when invoking them via <code>npm run-script</code>.</p></blockquote><p>如果第三方包在<code>package.json</code>中声明了<code>bin</code>字段:<code>命令名称 -> 本地文件名</code>的映射,如<code>bin: { "webpack": "bin/webpack.js" }</code></p><p>在执行安装<code>npm i xxx</code>时,会由包管理工具创建<code>.bin</code>目录,并创建一个可执行命令并将其<strong>软链接</strong>到目标文件</p><p>推荐阅读:<a href="https://juejin.cn/post/7078924628525056007" target="_blank" rel="noreferrer">三面面试官:运行 npm run xxx 的时候发生了什么?</a></p><h3 id="npm包的发布" tabindex="-1">npm包的发布 <a class="header-anchor" href="#npm包的发布" aria-label="Permalink to "npm包的发布""></a></h3><p>如果你希望发布自己的npm包,主要涉及到的命令有:</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">npm</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">init</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">-y</span><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;"># 初始化项目 生成package.json</span></span>
|
||
<span class="line"><span style="color:#B392F0;">npm</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">login</span><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;"># 登录自己的npm账号</span></span>
|
||
<span class="line"><span style="color:#B392F0;">npm</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">publish</span><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;"># 将包发布到npm上 后续版本更新也使用此命令</span></span>
|
||
<span class="line"><span style="color:#B392F0;">npm</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">unpublish</span><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;"># 取消发布 删除发布的npm包</span></span>
|
||
<span class="line"><span style="color:#B392F0;">npm</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">deprecate</span><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;"># 让发布的npm包过期</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">npm</span><span style="color:#24292E;"> </span><span style="color:#032F62;">init</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">-y</span><span style="color:#24292E;"> </span><span style="color:#6A737D;"># 初始化项目 生成package.json</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">npm</span><span style="color:#24292E;"> </span><span style="color:#032F62;">login</span><span style="color:#24292E;"> </span><span style="color:#6A737D;"># 登录自己的npm账号</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">npm</span><span style="color:#24292E;"> </span><span style="color:#032F62;">publish</span><span style="color:#24292E;"> </span><span style="color:#6A737D;"># 将包发布到npm上 后续版本更新也使用此命令</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">npm</span><span style="color:#24292E;"> </span><span style="color:#032F62;">unpublish</span><span style="color:#24292E;"> </span><span style="color:#6A737D;"># 取消发布 删除发布的npm包</span></span>
|
||
<span class="line"><span style="color:#6F42C1;">npm</span><span style="color:#24292E;"> </span><span style="color:#032F62;">deprecate</span><span style="color:#24292E;"> </span><span style="color:#6A737D;"># 让发布的npm包过期</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>执行<code>npm init -y</code>后,为我们生成的默认<code>package.json</code>如下:</p><div class="language-json vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">json</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#E1E4E8;">{</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"name"</span><span style="color:#E1E4E8;">: </span><span style="color:#9ECBFF;">"my-project"</span><span style="color:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"version"</span><span style="color:#E1E4E8;">: </span><span style="color:#9ECBFF;">"1.0.0"</span><span style="color:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"description"</span><span style="color:#E1E4E8;">: </span><span style="color:#9ECBFF;">""</span><span style="color:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"main"</span><span style="color:#E1E4E8;">: </span><span style="color:#9ECBFF;">"index.js"</span><span style="color:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"dependencies"</span><span style="color:#E1E4E8;">: {},</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"devDependencies"</span><span style="color:#E1E4E8;">: {},</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"scripts"</span><span style="color:#E1E4E8;">: {</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"test"</span><span style="color:#E1E4E8;">: </span><span style="color:#9ECBFF;">"echo </span><span style="color:#79B8FF;">\\"</span><span style="color:#9ECBFF;">Error: no test specified</span><span style="color:#79B8FF;">\\"</span><span style="color:#9ECBFF;"> && exit 1"</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> },</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"keywords"</span><span style="color:#E1E4E8;">: [],</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"author"</span><span style="color:#E1E4E8;">: </span><span style="color:#9ECBFF;">""</span><span style="color:#E1E4E8;">,</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">"license"</span><span style="color:#E1E4E8;">: </span><span style="color:#9ECBFF;">"ISC"</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">}</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#24292E;">{</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"name"</span><span style="color:#24292E;">: </span><span style="color:#032F62;">"my-project"</span><span style="color:#24292E;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"version"</span><span style="color:#24292E;">: </span><span style="color:#032F62;">"1.0.0"</span><span style="color:#24292E;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"description"</span><span style="color:#24292E;">: </span><span style="color:#032F62;">""</span><span style="color:#24292E;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"main"</span><span style="color:#24292E;">: </span><span style="color:#032F62;">"index.js"</span><span style="color:#24292E;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"dependencies"</span><span style="color:#24292E;">: {},</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"devDependencies"</span><span style="color:#24292E;">: {},</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"scripts"</span><span style="color:#24292E;">: {</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"test"</span><span style="color:#24292E;">: </span><span style="color:#032F62;">"echo </span><span style="color:#005CC5;">\\"</span><span style="color:#032F62;">Error: no test specified</span><span style="color:#005CC5;">\\"</span><span style="color:#032F62;"> && exit 1"</span></span>
|
||
<span class="line"><span style="color:#24292E;"> },</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"keywords"</span><span style="color:#24292E;">: [],</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"author"</span><span style="color:#24292E;">: </span><span style="color:#032F62;">""</span><span style="color:#24292E;">,</span></span>
|
||
<span class="line"><span style="color:#24292E;"> </span><span style="color:#005CC5;">"license"</span><span style="color:#24292E;">: </span><span style="color:#032F62;">"ISC"</span></span>
|
||
<span class="line"><span style="color:#24292E;">}</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>其中<code>keywords</code> <code>author</code> <code>license</code>都会展示在此包的npm网站上,除此之外还可以定义<code>homepage</code> <code>repository</code>字段</p><h3 id="npm包的开发调试" tabindex="-1">npm包的开发调试 <a class="header-anchor" href="#npm包的开发调试" aria-label="Permalink to "npm包的开发调试""></a></h3><p>在npm包的开发过程中,如果要调试代码,那我们不可能每次修改代码都通过<em>提交到npm后,重新下载到本地</em>来调试代码</p><p>一般来讲有三种解决方案:</p><ul><li>直接修改导入路径 简单粗暴 <ul><li>如:将之前的<code>import lodash from 'lodash-es'</code>修改为<code>import lodash from '... debug/lodash-es'</code></li><li>也可以修改<code>package.json</code>中的依赖版本为<code>file:包的路径</code></li><li>纯人工操作,容易误操作,不推荐</li></ul></li><li>通过<code>npm link</code>命令 软连接 <ul><li>首先在本地<strong>开发中的包项目</strong>根目录执行<code>npm link</code>,将提示:<code>success Registered "my-project".</code>成功注册名为<code>my-project</code>的包</li><li>随后,在<strong>引入了此包的项目</strong>根目录下执行<code>npm link "my-project"</code> 即可将当前项目的<code>node_modules</code>中的此包软连接到正在开发中的包的路径</li><li>在许多情况下可能有效,但它通常会带来严重的限制和依赖关系解决、文件系统之间的符号链接互操作性等问题</li></ul></li><li>yalc模拟发布npm包 <ul><li>yalc可以将模拟发布的npm包存放在全局存储中,这样可以得到类似于发布-安装的效果</li><li>可以避免<code>npm link</code>导致的依赖关系问题 <ul><li>全局安装<code>npm i yalc -g</code> 模拟发布<code>yalc publish</code></li><li>引入方法1 <code>yalc link my-project</code>:向<code>node_modules</code>创建指向包内容的<strong>符号链接</strong>,并且不会修改<code>package.json</code>中的内容</li><li>引入方法2 <code>yalc add my-project</code>:将包拉到当前项目根目录<code>.yalc</code>中,并将 <code>file:.yalc/my-project</code> 依赖关系注入到<code>package.json</code>中(<code>file:包的路径</code>)</li></ul></li></ul></li></ul><h3 id="pnpm" tabindex="-1">PNPM <a class="header-anchor" href="#pnpm" aria-label="Permalink to "PNPM""></a></h3><h4 id="解决了哪些痛点" tabindex="-1">解决了哪些痛点 <a class="header-anchor" href="#解决了哪些痛点" aria-label="Permalink to "解决了哪些痛点""></a></h4><p>传统包管理工具如npm yarn都有以下两个痛点:</p><ul><li><code>node_modules</code>太重 硬盘压力较大</li><li>幽灵依赖(为了复用 所有的包都被铺平在<code>node_modules</code>中 导致即使某些间接依赖虽然没有被安装 却能正常引入)</li></ul><p>PNPM(performant npm)有以下优点:</p><ul><li>比其他包管理器更快</li><li><code>node_modules</code>中的文件链接自特定的内容寻址存储库</li><li>支持 monorepos(单仓多包)</li><li>PNPM创建了一个非平铺的<code>node_modules</code> 代码无法访问任意包(避免了幽灵依赖)</li></ul><h4 id="硬链接和软链接" tabindex="-1">硬链接和软链接 <a class="header-anchor" href="#硬链接和软链接" aria-label="Permalink to "硬链接和软链接""></a></h4><ul><li>硬链接 (hard link) <ul><li>电脑文件系统中的多个文件平等地共享同一个文件存储单元</li><li>删除一个文件名字后,还可以通过其他名字继续访问该文件</li></ul></li><li>符号链接 (软链接 soft link、Symbolic link) <ul><li>符号链接 是一类特殊的文件</li><li>其包含有一条以绝对路径或者相对路径的形式<strong>指向其他文件或者目录的引用</strong></li></ul></li></ul><p><img src="`+e+'" alt="hard-link and soft-link"></p><p>操作系统使用不同的<strong>文件系统</strong>,<strong>对真实的硬盘读写操作做了一层抽象</strong>,借由文件系统,我们得以方便地操作和访问文件的真实数据</p><ul><li>软链接例:你为一个文件创建了一个快捷方式,这个快捷方式本质上保存着目标文件的路径 <ul><li>访问快捷方式的本质是通过路径访问原文件</li><li>删除快捷方式时,不会对原文件的数据产生影响</li></ul></li><li>硬链接例:<code>F:/Video/abc.mp4</code> 和 <code>F:/Video/cba.mp4</code>指向了同一片硬盘数据空间 <ul><li>在文件系统中删除<code>abc.mp4</code>或<code>cba.mp4</code>之一,并<strong>不会影响到其他文件对该片数据空间的读取</strong></li><li>注意:硬链接不是拷贝,文件拷贝意味着<strong>有新的数据空间在硬盘上被开辟</strong>,拷贝出的文件和原文件指向不同的数据空间</li></ul></li></ul><h4 id="实操硬链接和软链接" tabindex="-1">实操硬链接和软链接 <a class="header-anchor" href="#实操硬链接和软链接" aria-label="Permalink to "实操硬链接和软链接""></a></h4><ul><li>文件的拷贝 <ul><li>Windows: <code>copy foo.js foo_copy.js</code></li><li>MacOS: <code>cp foo.js foo_copy.js</code></li></ul></li><li>文件的硬链接 <ul><li>Windows: <code>mklink /H aaa_hard.js aaa.js</code></li><li>MacOS: <code>ln foo.js foo_hard.js</code></li></ul></li><li>文件的软链接 <ul><li>Windows: <code>mklink aaa_soft.js aaa.js</code></li><li>MacOS: <code>ln -s foo.js foo_copy.js</code></li></ul></li></ul><p>打开符号链接文件,会直接跳转到原文件,且符号链接文件不可写</p><h4 id="pnpm的工作细节" tabindex="-1">PNPM的工作细节 <a class="header-anchor" href="#pnpm的工作细节" aria-label="Permalink to "PNPM的工作细节""></a></h4><h5 id="硬链接" tabindex="-1">硬链接 <a class="header-anchor" href="#硬链接" aria-label="Permalink to "硬链接""></a></h5><ul><li>当使用npm或yarn时,如果有100个项目,且每个项目都有一个相同的依赖包 <ul><li>此依赖包将会在你的硬盘上存储100份,占据100份硬盘数据空间</li></ul></li><li>当使用pnpm时,此依赖包将被存储在一个统一的位置 <ul><li>所有其他项目引用该版本的依赖,将使用这同一份文件</li><li>如果依赖有不同版本,则不同版本的依赖包分别存储</li></ul></li></ul><p>这样,多个项目之间可以方便地共享相同版本的依赖包,减小了硬盘的压力。</p><p>以安装<code>axios</code>为例,我们在某个项目中执行了<code>pnpm add axios</code></p><ul><li>PNPM拉取Axios的代码 将其保存在<strong>全局仓库</strong><code>.pnpm/axios</code>中,并且<strong>硬链接</strong>到硬盘中的数据文件</li><li>在<strong>当前项目</strong>中的<code>node_modules</code>创建文件夹<code>axios</code>,将其中的文件<strong>硬链接</strong>到硬盘中的相同位置</li><li>硬链接是不能操作目录的 目录需要创建 而其中的文件可以使用硬链接</li><li>以后如果有其他项目也用到了相同版本的<code>axios</code>,在执行<code>pnpm add axios</code>后:只需要在各自的<code>node_modules</code>创建硬链接到那片数据空间即可</li></ul><h5 id="非扁平的node-modules" tabindex="-1">非扁平的node_modules <a class="header-anchor" href="#非扁平的node-modules" aria-label="Permalink to "非扁平的node_modules""></a></h5><ul><li>使用npm或yarn Classic安装依赖包时 所有包都将被提升到<code>node_modules</code>的根目录下 <ul><li>这是为了防止依赖之间多层嵌套,才想出的解决方案</li><li>这就导致:源码可以访问到间接依赖,访问到本不属于此项目的依赖包,导致幽灵依赖问题</li></ul></li><li>而PNPM仅有项目依赖会放在<code>node_modules</code>目录下 <ul><li>这些在<code>node_modules</code>根目录中的依赖包,是<code>node_modules/.pnpm</code>中硬链接文件的的<strong>符号链接</strong></li><li>在<code>node_modules/.pnpm</code>中,包含了附加版本信息的真实文件(硬链接到硬盘数据的文件)</li><li>所有间接依赖,都通过软链接的方式,链接到被铺平在<code>.pnpm</code>文件夹中对应版本的硬链接文件上</li></ul></li></ul><p><img src="'+c+`" alt="how pnpm works"></p><h4 id="常用命令" tabindex="-1">常用命令 <a class="header-anchor" href="#常用命令" aria-label="Permalink to "常用命令""></a></h4><ul><li><code>pnpm === npm init -y</code> 项目初始化</li><li><code>pnpm install === npm i</code> 安装项目依赖</li><li><code>pnpm add <pkg> === npm install <pkg></code> 安装npm包</li><li><code>pnpm remove <pkg> === npm uninstall <pkg></code> 移除npm包</li><li><code>pnpm <script> === npm run <script></code> 执行项目脚本</li></ul><h4 id="存储store的位置" tabindex="-1">存储Store的位置 <a class="header-anchor" href="#存储store的位置" aria-label="Permalink to "存储Store的位置""></a></h4><ul><li>在PNPM 7.0之前,统一的存储位置是<code>~/.pnpm-store</code><ul><li>例如<code>C:/Users/Ziu/.pnpm-store</code><ul><li><code>~/path === $HOME/path</code> 用户目录</li><li><code>./path</code> 相对路径</li><li><code>/path</code> 根目录</li></ul></li></ul></li><li>在7.0版本之后,统一存储位置在<code><pnpm home directory>/store</code><ul><li>Linux: <code>~/.local/share/pnpm/store</code></li><li>Windows: <code>%LOCALAPPDATA%/pnpm/store</code></li><li>MacOS: <code>~/Library/pnpm/store</code></li></ul></li></ul><p>可以通过命令行,获取到这个目录:</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">pnpm</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">store</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">path</span><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;"># 获取到硬链接store的路径</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">pnpm</span><span style="color:#24292E;"> </span><span style="color:#032F62;">store</span><span style="color:#24292E;"> </span><span style="color:#032F62;">path</span><span style="color:#24292E;"> </span><span style="color:#6A737D;"># 获取到硬链接store的路径</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>如果当前目录创建了很多项目,尽管PNPM已经节省了空间,但是由于所有依赖都通过硬链接存放在同一个store中</p><p>随着文件数量增长,导致store越来越大,可以通过命令行,移除冗余文件造成的体积占用</p><div class="language-sh vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#B392F0;">pnpm</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">store</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">prune</span><span style="color:#E1E4E8;"> </span><span style="color:#6A737D;"># prune修剪 从store中删除当前未被引用的包 以释放store的空间</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#6F42C1;">pnpm</span><span style="color:#24292E;"> </span><span style="color:#032F62;">store</span><span style="color:#24292E;"> </span><span style="color:#032F62;">prune</span><span style="color:#24292E;"> </span><span style="color:#6A737D;"># prune修剪 从store中删除当前未被引用的包 以释放store的空间</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><h2 id="系统学习webpack" tabindex="-1">系统学习Webpack <a class="header-anchor" href="#系统学习webpack" aria-label="Permalink to "系统学习Webpack""></a></h2><ul><li>认识webpack工具</li><li>webpack基本打包</li><li>webpack配置文件</li><li>编写和打包CSS文件</li><li>编写Less文件</li><li>PostCSS工具处理CSS</li></ul><h3 id="node内置模块-path" tabindex="-1">Node内置模块 path <a class="header-anchor" href="#node内置模块-path" aria-label="Permalink to "Node内置模块 path""></a></h3><ul><li>path模块用于对路径和文件进行处理</li><li>在不同系统上,文件路径的分隔符是不同的 <ul><li>MacOS和Linux的分隔符是<code>/</code></li><li>Windows上的分隔符是<code>\\</code> <code>\\\\</code> 目前也支持 <code>/</code></li></ul></li></ul><p>可以通过Node的path模块来抹平不同平台的差异</p><p>常用API</p><ul><li><p><code>path.extname</code> 后缀名</p></li><li><p><code>path.basename</code> 文件名</p></li><li><p><code>path.dirname</code> 文件夹名</p></li><li><p><code>path.join</code> 拼接多个路径</p><ul><li>下例中,由于<code>p2</code>通过<code>../</code>指定了上一级路径,所以从<code>abc</code>紧接着就是<code>why</code>了</li></ul></li></ul><div class="language-js vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki github-dark vp-code-dark"><code><span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">path</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#B392F0;">require</span><span style="color:#E1E4E8;">(</span><span style="color:#9ECBFF;">'path'</span><span style="color:#E1E4E8;">)</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">p1</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'abc/cba'</span></span>
|
||
<span class="line"><span style="color:#F97583;">const</span><span style="color:#E1E4E8;"> </span><span style="color:#79B8FF;">p2</span><span style="color:#E1E4E8;"> </span><span style="color:#F97583;">=</span><span style="color:#E1E4E8;"> </span><span style="color:#9ECBFF;">'../why/kobe/james.txt'</span></span>
|
||
<span class="line"><span style="color:#E1E4E8;">console.</span><span style="color:#B392F0;">log</span><span style="color:#E1E4E8;">(path.</span><span style="color:#B392F0;">join</span><span style="color:#E1E4E8;">(p1, p2)) </span><span style="color:#6A737D;">// \\\\abc\\\\why\\\\kobe\\\\james.txt</span></span></code></pre><pre class="shiki github-light vp-code-light"><code><span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">path</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#6F42C1;">require</span><span style="color:#24292E;">(</span><span style="color:#032F62;">'path'</span><span style="color:#24292E;">)</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">p1</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'abc/cba'</span></span>
|
||
<span class="line"><span style="color:#D73A49;">const</span><span style="color:#24292E;"> </span><span style="color:#005CC5;">p2</span><span style="color:#24292E;"> </span><span style="color:#D73A49;">=</span><span style="color:#24292E;"> </span><span style="color:#032F62;">'../why/kobe/james.txt'</span></span>
|
||
<span class="line"><span style="color:#24292E;">console.</span><span style="color:#6F42C1;">log</span><span style="color:#24292E;">(path.</span><span style="color:#6F42C1;">join</span><span style="color:#24292E;">(p1, p2)) </span><span style="color:#6A737D;">// \\\\abc\\\\why\\\\kobe\\\\james.txt</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><ul><li><code>path.resolve</code> 将多个路径片段解析、拼接为一个绝对路径 <ul><li><strong>从右往左</strong>处理传入的路径序列,每个路径依次被解析,直到构造完成一个绝对路径</li><li>如果在处理完所有给定path的段之后,还没有生成绝对路径,则使用当前工作目录</li><li>生成的路径被规范化并删除尾部斜杠,零长度path段被忽略</li><li>如果没有传递path段,则<code>path.resolve()</code>将返回当前工作目录的绝对路径</li></ul></li></ul><h3 id="初识webpack" tabindex="-1">初识Webpack <a class="header-anchor" href="#初识webpack" aria-label="Permalink to "初识Webpack""></a></h3><p>path模块在webpack的使用中有较大作用,所以预先介绍了一下,下面正式进入Webpack的学习</p><ul><li>Webpack能够帮助我们进行模块化开发</li><li>高级特性提升开发效率和代码安全性、可维护性,如 ES6+ TypeScript SASS Less 等都需要构建工具</li><li>实时文件监听(开发热更新)、代码压缩合并等</li></ul>`,254),i=[t];function d(E,y,u,m,b,F){return n(),a("div",null,i)}const C=s(r,[["render",d]]);export{g as __pageData,C as default};
|