将 requirejs 和普通 js 文件合并在一起



我正在开发一个小网站,主HTML页面基本上看起来像这样:

<html lang="en">
<head>
<script src="ace.js" type="text/javascript"><script>
<script src="ext-language_tools.js" type="textjavascript"></script>
<script src="mode-mongo.js" type="text/javascript"></script>
<script src="playground.js" type="text/javascript"></script>
<script type="text/javascript">

window.onload = function() {

ace.config.setModuleUrl("ace/mode/mongo", "mode-mongo.js")

configEditor = ace.edit(document.getElementById("editor"), {
"mode": "ace/mode/mongo",
"useWorker": false
})
}
</script>
</head>
<body>
<div class="editor">
</body>
</html>

(真正的在这里可见)。

以下是未缩小的文件:

  • 王牌.js
  • 分language_tools.js
  • 摩登蒙戈.js
  • 游乐场.js

前 3 个 js 文件使用 requirejs,第 4 个只是普通的 js

有没有办法将这 4 个文件合并到一个文件中,以便在我的 HTML 中包含这样的东西?

<html lang="en">
<head>
<script src="bundle.js" type="text/javascript"><script>
<script type="text/javascript">

window.onload = function() {
configEditor = ace.edit(document.getElementById("editor"), {
"mode": "ace/mode/mongo",
"useWorker": false
})
}
</script>
</head>
<body>
<div class="editor">
</body>
</html>

编辑

我的目标是在单个HTTP请求中一次加载所有这些js代码

我有点困惑。您说您正在对前 3 个文件使用 requirejs,但这不是我对如何使用requirejs的理解。你通常会有一个主要的JavaScript文件(我们称之为main.js),你的HTML将加载一个JavaScript文件,即require.js文件,它将指定要加载的主.js文件:

<html lang="en">
<head>
<script src="require.js" data-main="main"><script>
<!-- The following does not currently use require.js: -->
<script src="playground.js"><script>
<script>

window.onload = function() {
configEditor = ace.edit(document.getElementById("editor"), {
"mode": "ace/mode/mongo",
"useWorker": false
})
}
</script>
</head>
<body>
<div class="editor">
</body>
</html>

然后在main.js中,您将使用require()(或requirejs())来加载需要运行的任何其他脚本。例如:

require(["ace"], function(ace) {
//This function is called when scripts/ace.js is loaded.
//If ace.js calls define(), then this function is not fired until
//ace's dependencies have loaded, and the ace argument will hold
//the module value for "ace".
});

需要ace模块的window.onload事件处理程序将被移动到main.js文件中。

现在,如果您想将 4 个文件捆绑到一个文件中,那么假设您已经安装了Node.js最简单的方法是首先使用 npm 安装requirejs

npm install -g requirejs

接下来安装丑陋:

npm install uglify-js -g

然后在包含脚本的目录中创建一个新的 JavaScript 文件main.js

require(['ace', 'ext-language-tools', 'mode-mongo', 'playground'], function(ace) {
window.onload = function() {
configEditor = ace.edit(document.getElementById("editor"), {
"mode": "ace/mode/mongo",
"useWorker": false
});
};
});    

然后从脚本目录执行:

r.js -o name=main out=bundle.js

如果您在 Windows 下运行,则需要将上述r.js替换为r.js.cmd。这应该为您提供一个缩小的文件包.js。如果您不希望缩小文件,则:

r.js -o name=main out=bundle.js optimize=none

然后修改您的 HTML 以如下所示:

<html lang="en">
<head>
<script src="require.js" data-main="bundle"><script>
</head>
<body>
<div class="editor">
</body>
</html>

当然,您不需要main.js中的window.onload事件:

require(['ace', 'ext-language-tools', 'mode-mongo', 'playground'], function() {});

然后你的 HTML 变成:

<html lang="en">
<head>
<script src="require.js" data-main="bundle"><script>
<script>
require(['ace'], function(ace) {
window.onload = function() {
configEditor = ace.edit(document.getElementById("editor"), {
"mode": "ace/mode/mongo",
"useWorker": false
});
};
});
</script>
</head>
<body>
<div class="editor">
</body>
</html>

@Booboo的答案大多是正确的。但我想加上我的 5 美分:

  1. ace.js在您的存储库中,并且您的问题已经捆绑在一起!它实际上并没有使用requirejs。一切都已经在里面了。您可以在DevTools中自行查看它:只有一个网络请求。因此,它不适用于requirejs文档和@Booboo答案建议的设置。
  2. 为了能够使用requirejs的捆绑机制,您需要添加ace的来源。
  3. 你也可以,但你不必使用r.js.目前尚不清楚您的目标是什么。但是,如果出于某种原因,您只想在 html 中包含一个脚本入口点(不确定为什么需要这个) -<script src="require.js" data-main="main" />就足够了。
  4. 再说一次,由于你的目标不明确,让我建议 - 不要这样做。ace项目中只有 2 个附加文件。其他的都是你的,所以只捆绑它们。如果你将你的代码捆绑在一起,那么你的代码将ace.js,那么每次你的代码更改时,你的用户将不得不一次又一次地下载所有ace.js的KB,因为浏览器将无法使用它的缓存版本。捆绑包的主要思想(也是 CDN 背后的原因之一)正是为了从长远来看最大限度地减少请求数量。如果您担心新用户不会再来,因为您的网站在第一次访问时初始化的时间稍长......好吧,也许速度不是您主要关心的问题。此外,浏览器可以有 6 个并行连接,因此一个捆绑包实际上会减慢您的网站速度。

这是一个有趣的问题,因为在JavaScript和Web开发中有很多潜在的解决方案跨越了几个时代和哲学。我将讨论最简单和最古老的文件串联,并简要介绍 RequireJS,以及使用专用 Web 捆绑器的更现代方法。还有一个未陈述的基本假设,即为什么你觉得你需要捆绑它 - 可能有一些文件加载的假设可能不正确,特别是对于HTTP/2。

快速方式

如果你想要一些快速、简单和老派的东西,你可以将所有的JavaScript文件组合(连接)在一起。这基本上就是你初始网页中发生的事情:浏览器下载所有JavaScript文件并按顺序运行它们。

要使用 Unix/Linux/OS X 进行连接:

cat path/to/ace.js  <(echo) 
path/to/ext-language_tools.js  <(echo) 
path/to/mode-mongo.js  <(echo) 
path/to/playground.js 
> path/to/bundle.js

(如果删除,则可以将它们全部合并到一行中。如果您知道文件以换行符结尾,也可以省略<(echo))

或者,您可以手动将文件复制并粘贴到一个大文件中。

需要JS的方式

值得一提的是 RequireJS 的做事方式,它使用require语句,因为这是 ace.js 开发的哲学。使用此理念,文件旨在作为模块保持分离,并根据需要加载。其他答案更详细地解释了这种方法,尽管我要补充一点,捆绑似乎不是使用 RequireJS 的惯用方式——库最初打算(尽管不需要)将模块拆分为不同的文件。

网络捆绑器方式

近年来,人们已经采用Web捆绑器(如Webpack,parcel,rollup等)来管理多个文件和依赖项。这些工具旨在输出单个 Web 包,并为此提供了许多不错的、可定制的功能。他们可能需要一些工作才能启动和运行,并且需要使用 CommonJS 插件来require工作。例如,请参阅此处以获取使用webpack的ace。

您需要捆绑吗?

根据您的顾虑和情况,捆绑可能不需要您需要的优化。从历史上看,捆绑被用作最小化网络请求的一种方式,因为网络连接的数量是有限的,有时文件请求其他文件,导致串行加载。其中许多问题都通过HTTP/2得到解决。只要确保您的 Web 服务器支持 HTTP/2,并且您正在该服务器上提供所有文件即可。有关此内容的详细信息,请参阅此问题。您可能最关心它在实践中的运作方式,因此您可能希望以任何一种方式对其进行基准测试,但您可能没有获得太多收益。

我们可以简单地使用 webpack 来获取您想要的东西

带有香草的网页包

module.exports = {
entry: ["./ace.js", "./playground.js" ....],
output: {
filename: "bundle.js"
}
}

您可以在一个 js 文件中require它们,并在模板中引用它。

像这样:

捆绑.js:

require(../ace.js);
// other files
require(../playground.js);

你可以同时使用requiresource script

首先,配置您的webpack.config.jsWebpack 文档

const path = require('path');
const toml = require('toml');
const yaml = require('yamljs');
const json5 = require('json5');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
stats: 'errors-only',
mode: 'development',
entry: './src/index.js',
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 3000,
},
plugins: [
new HtmlWebpackPlugin({
title: 'Artificial Intelligence',
}),
],
output: {
filename: '[contenthash].bundle.js',
path: path.resolve(__dirname, 'public'),
},
module: {
rules: [
{
test: /.css$/i,
use: ['style-loader', 'css-loader'],
},
{
test: /.toml$/i,
type: 'json',
parser: {
parse: toml.parse,
},
},
{
test: /.yaml$/i,
type: 'json',
parser: {
parse: yaml.parse,
},
},
{
test: /.json5$/i,
type: 'json',
parser: {
parse: json5.parse,
},
},
],
},
};

在第二步中,require您需要的文件

// Es5
const x = require('x');
const y = require('y');
// Es6
import * as x from 'x';
import y from 'y';
import { z } from 'z';

使用script tag而不是importing

<html lang="en">
<head>
...
</head>
<body>
<script src="x.js"></script>
<script src="y.js"></script>
<script>
const x = new X();
</script>
</body>
</html>

注意:脚本毕竟必须执行

您还可以use the scripts文件中imported in the script tag

应用.js

const x = new X();
cosnt y = new Y();

列出不需要的文件,如下所示