JavaScript 中的模块——CommonJS 和 ESmodules(下)

本文探讨了JavaScript中的模块使用,包括如何在HTML中实现模块功能,以及为何在生产环境中需要模块打包工具。通过示例解释了模块打包器如Webpack的工作原理,展示了如何将多个模块文件合并成一个文件以优化性能。

使用模块

好的,现在我们已经清楚了可用的不同类型的模块以及它们是如何工作的,让我们看看如何使用 HMTL 和 Vanilla JS 在网站中实现模块。

让我们创建一个简单的 HTML 文件,其中包含一个标题、两个按钮和一个链接到我们main.js文件的脚本标记。

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>I'm just a test...</h1>
    <button id="isAlive">Is mod1 alive?</button>
    <button id="isRolling">Is mod1 rolling?</button>
    <script src="./main.js" type="module"></script>
</body>
</html> 

请注意我type="module"在脚本标签上声明的事实。我们需要这样做才能使用 JS 模块功能。如果不这样做,我们将收到如下错误:

Uncaught SyntaxError: Cannot use import statement outside a module 

如果我们打开我们的 HTML 文件,我们应该得到如下内容:
截图-2

我们的main.js文件将包含以下代码:

// main.js
import { mod1Function, mod1Function2 } from './mod1.js'

const testFunction = () => console.log('Im the main function')

document.getElementById('isAlive').addEventListener('click', () => mod1Function())
document.getElementById('isRolling').addEventListener('click', () => mod1Function2())

testFunction() 

我们只是为每个按钮添加一个单击事件侦听器,以便执行来自mod1.js文件的函数。

好的,现在我们可以提供我们的 HTML 文件,看看这是否有效。我们需要提供文件,我们不能只在浏览器中打开 HTML,因为我们会收到这样的 CORS 错误:

Access to script at ... from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, brave, chrome-untrusted, https. 

为了快速提供服务,您可以使用Live 服务器VS 代码扩展,或者通过运行npm init -y然后运行来创建一个 Node 应用程序npx serve

无论如何,一旦提供了文件,我们就可以单击每个按钮并测试我们的函数是否正确执行。我们的控制台应该是这样的:
截图_1-1

但还有一件事。如果我们进入浏览器开发者工具的网络选项卡,通过JS文件过滤,我们可以看到网站正在加载两个文件,main.js并且mod1.js
截图_3

当然,如果我们要使用每个文件中的代码,两者都需要加载——但这不是最好的做法。那是因为浏览器需要执行两个不同的请求来加载所有必需的 JS。

我们应该始终尝试将请求减少到最低限度,以提高我们项目的性能。因此,让我们看看如何在模块捆绑器的帮助下做到这一点。

旁注:如果您想要视频解释,Kent C Dodds 有一个很棒的。我真的建议你关注他,他是最好的 JS 老师之一。这是 Fireship的另一个很酷的视频。😉

捆绑模块

如前所述,将我们的代码分成模块很好,因为我们的代码库将更有条理,并且更容易重用我们的代码。

但这些只是项目开发阶段的优势。在生产环境中,模块并不是最好的选择,因为强制浏览器对每个 JS 文件进行请求可能会损害网站的性能。

使用模块捆绑器可以轻松解决此问题。简而言之,模块捆绑器是将 JS 模块作为输入并将它们组合到单个文件中的程序(许多模块捆绑器具有更多功能,但这是它们的核心概念)。

多亏了这一点,作为开发人员,我们可以对项目进行编码,将其划分为组织良好的部分,然后运行模块捆绑器以获得将在生产中使用的最终代码。

将“开发代码”转换为“生产代码”的这一步骤通常被认为是“构建”。

有很多选项可以使用(例如BrowserifyParcelRollup.jsSnowpack …),但使用最广泛的是Webpack。因此,让我们看一个使用 Webpack 的示例。

  • 旁注1:如果您想深入了解模块捆绑器及其工作原理,Fireship 的这个精彩视频可能是一个不错的起点。
  • 旁注 2:Webpack 是一个非常强大和复杂的工具,除了捆绑 JS 文件之外,它还可以做很多事情。如果您想了解更多信息,请查看他们的文档。

太好了,所以现在我们可以通过运行npm init -y. 然后我们需要通过运行来安装 Webpack 和 Webpack CLI npm i --save-dev webpack webpack-cli

接下来我们将创建一个webpack.config.js文件并将此代码放入其中:

/* webpack.config.js */
const path = require('path');

module.exports = {
  entry: './main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
}; 

该文件将负责 Webpack 的配置以及它在我们的应用程序中的工作方式。

我们在这里首先要做的是设置入口文件(entry: './main.js')。Webpack 将从读取该文件开始,然后分析所有依赖项(从该文件导入的模块)。换句话说,入口文件是我们导入所有其他模块的主要 JS 文件。

然后我们声明输出——首先声明将存储它的路径,然后声明捆绑文件的名称。

output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
}, 

极好的!现在让我们转到我们的package.json文件并添加一个build脚本,如下所示:

{
  "name": "testappv2",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.72.0",
    "webpack-cli": "^4.9.2"
  }
} 

然后我们可以回到我们的终端并运行npm run build。这应该dist在我们的项目中创建一个目录,并在其中创建一个bundle.js文件。

如果您签出该文件,您将在其中看到以下代码:

(()=>{"use strict";document.getElementById("isAlive").addEventListener("click",(()=>console.log("Mod1 is alive!"))),document.getElementById("isRolling").addEventListener("click",(()=>console.log("Mod1 is rolling, baby!"))),console.log("Im the main function")})(); 

您会看到它实际上与我们在文件中分发的代码相同,但都捆绑在一个文件中并进行了缩小。

剩下的唯一事情就是更改我们index.html文件中的脚本标签,以便它现在使用捆绑的 JS,如下所示:

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>I'm just a test...</h1>
    <button id="isAlive">Is mod1 alive?</button>
    <button id="isRolling">Is mod1 rolling?</button>
    <script src="./dist/bundle.js" type="module"></script>
</body>
</html> 

现在我们可以再次提供它,检查 JS 是否仍然可以正常工作,如果我们再次打开网络选项卡,我们应该看到只有一个文件正在加载!=D [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g27eD7Ca-1653875048451)(https://juejin.cn/)]

image.png 我希望这个简单的例子能帮助您理解模块捆绑器的相关性,以及它们如何帮助我们将模块化架构的出色开发经验与良好的站点性能结合起来。

结论

好了,我们今天就完成了。在本文中,我们了解了模块是什么,它们为什么很酷,在 JavaScript 中实现模块的不同方式,以及将我们的代码与 Webpack 捆绑在一起的实际示例。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值