简体   繁体   English

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

[英]Merging requirejs and plain js file together

I'm developping a small website, and the main HTML page basically looks like this:我正在开发一个小网站,主要的 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>

( real one is visible here ). (真正的在这里可见)。

Here are the unminified files:以下是未缩小的文件:

The first 3 js files use requirejs , the 4th is just plain js前 3 个 js 文件使用requirejs ,第 4 个只是普通的 js

Is there a way to merge those 4 files into a single file in order to have something like this in my HTML instead ?有没有办法将这 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>

Edit编辑

My goal is to load all this js code at once in a single HTTP request我的目标是在单个 HTTP 请求中一次加载所有这些 js 代码

You can require them in one js file and reference that in your template.您可以在一个 js 文件中require它们并在您的模板中引用它。

Something like this:像这样的东西:

bundle.js:捆绑.js:

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

I am a bit confused.我有点困惑。 You say you are using requirejs for the first 3 files, but this is not my understanding of how requirejs is used.你说你在前 3 个文件中使用了requirejs ,但这不是我对requirejs是如何使用的理解。 You would normally have a main JavaScript file (let's call it main.js ) and your HTML would load a single JavaScript file, ie the require.js file, which would specify the main.js file to be loaded:您通常会有一个主要的 JavaScript 文件(我们称之为main.js )并且您的 HTML 将加载一个 JavaScript 文件,即require.js文件,该文件将指定要加载的main.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>

And then inside of main.js , you would use require() (or requirejs() ) to load any other scripts you need to run.然后在main.js内部,您将使用require() (或requirejs() )加载您需要运行的任何其他脚本。 For example:例如:

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".
});

And the window.onload event handler, which requires the ace module, would be moved to inside main.js file.需要ace模块的window.onload事件处理程序将被移动到main.js文件中。

Now if you want to bundle the 4 files into a single file, then assuming you have Node.js installed the easiest way to proceed is to first install requirejs using npm:现在,如果您想将这 4 个文件捆绑到一个文件中,那么假设您安装了Node.js ,最简单的方法是首先使用 npm 安装requirejs

npm install -g requirejs

Next install uglify :接下来安装uglify

npm install uglify-js -g

Then create a new JavaScript file main.js in the directory that has your scripts:然后在包含您的脚本的目录中创建一个新的 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
        });
    };
});    

Then execute from the scripts directory:然后从脚本目录执行:

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

If you are running under Windows, you will need to replace r.js above with r.js.cmd .如果您在Windows下运行,则需要更换r.js以上r.js.cmd This should give you a single, minified file bundle.js .这应该会给你一个单一的、缩小的文件bundle.js If you don't want the file minified then:如果您不想缩小文件,则:

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

Then modify your HTML to look something like:然后将您的 HTML 修改为如下所示:

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

Of course, you do not need the window.onload event in your main.js :当然,您不需要main.jswindow.onload事件:

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

And then your HTML becomes:然后你的 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's answer is mostly correct. @Booboo 的回答大部分是正确的。 But I'd like to add my 5 cents:但我想加上我的 5 美分:

  1. ace.js in your repo, and in your question is already bundled! ace.js在您的 repo 中,并且在您的问题中已经捆绑! It doesn't actually use the requirejs .它实际上并不使用requirejs Everything is already inside.一切都已经在里面了。 You can see it by yourself in the DevTools : there will be only one network request.您可以在DevTools 中自行查看:只有一个网络请求。 And as such it won't work with the setup suggested by the requirejs s docs and the @Booboo's answer.因此,它不适用于requirejs的文档和@Booboo 的回答所建议的设置。
  2. To be able to use the requirejs 's bundle mechanism you'll need to add the sources of the ace .为了能够使用requirejs的捆绑机制,您需要添加ace的来源。
  3. Also you can, but you don't have to use the r.js .你也可以,但你不必使用r.js It's not clear what is your goal.不清楚你的目标是什么。 But if for some reason you just want a single script entry point in your html (not sure why would you need this) - <script src="require.js" data-main="main" /> will be enough.但是,如果出于某种原因,您只想在 html 中使用单个脚本入口点(不知道为什么需要这个) - <script src="require.js" data-main="main" />就足够了。
  4. And again, as your goal is unclear, let me suggest - don't do this.再说一次,由于您的目标不明确,让我建议 - 不要这样做。 There are only 2 additional files from the ace project. ace项目中只有 2 个附加文件。 Others are yours, so bundle only them.其他人是你的,所以只捆绑他们。 If you'll bundle your code will the ace.js , then every time your code changes your users will have to download all the KB's of ace.js again and again, because browser won't be able to use a cached version of it.如果您将ace.js的代码捆绑ace.js ,那么每次您的代码更改时,您的用户都必须一次又一次地下载ace.js所有知识库,因为浏览器将无法使用它的缓存版本. And the main idea of the bundles (and also one of the reasons behind CDN) is exactly about minimizing the number of requests in the long run .捆绑包的主要思想(也是 CDN 背后的原因之一)正是关于从长远来看最大限度地减少请求数量。 And if your worry that new users won't come again because your site took a little bit longer to initialize on their first visit... well, maybe the speed is not your main concern.如果您担心新用户不会再次访问,因为您的网站在他们第一次访问时需要更长的时间来初始化...好吧,也许速度不是您主要关心的问题。 Also, there can be 6 parallel connections from the browser, so one bundle can actually slow your site down.此外,浏览器可能有 6 个并行连接,因此一个捆绑包实际上会降低您的网站速度。

This is an interesting question, since there are a bunch of potential solutions that span a few eras and philosophies in JavaScript and Web development.这是一个有趣的问题,因为在 JavaScript 和 Web 开发中,有许多跨越几个时代和哲学的潜在解决方案。 I'll talk about about the easiest and oldest, file concatenation, and briefly touch upon RequireJS, and more modern approaches of using dedicated web bundlers.我将讨论最简单和最古老的文件连接,并简要介绍 RequireJS,以及使用专用 Web 捆绑器的更现代方法。 There's also the unstated, underlying assumption of why you feel you need to bundle it-- there might be some assumptions of file loading which might not be true, particularly with HTTP/2.还有一个未说明的潜在假设,即为什么您觉得需要捆绑它——可能有一些文件加载​​假设可能不正确,尤其是对于 HTTP/2。

The Quick Way快捷方式

If you want something quick, easy, and old school, you can just combine (concatenate) all of your JavaScript files together.如果您想要快速、简单和老派的东西,您可以将所有 JavaScript 文件组合(连接)在一起。 That's essentially what's happening in your initial web page: the browser downloads all of the JavaScript files and runs them in order.这基本上就是您的初始网页中发生的事情:浏览器下载所有 JavaScript 文件并按顺序运行它们。

To concatenate using Unix/Linux/OS X:要使用 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

(You can combine them all on one line if you remove the \\ s. You can also omit the <(echo) if you know the file ends with a new line) (如果删除\\ s,则可以将它们全部合并在一行中。如果您知道文件以新行结尾,也可以省略<(echo)

The RequireJS Way RequireJS 方式

It bears mentioning the RequireJS way of doing things, that uses require statements, since that's the philosophy that ace.js is developed under.值得一提的是 RequireJS 的做事方式,它使用require语句,因为这是 ace.js 的开发理念。 Using this philosophy, files are intended to stay separated as modules and are loaded as needed.使用这种理念,文件旨在作为模块保持分离并根据需要加载。 Other answers explain this approach in more detail, though I'll add that bundling doesn't seem to be the idiomatic way to use RequireJS-- the library originally intended (though doesn't require) modules to be split into different files.其他答案更详细地解释了这种方法,但我会补充说,捆绑似乎不是使用 RequireJS 的惯用方式——库最初打算(尽管不需要)将模块拆分为不同的文件。

The Web Bundler Way Web Bundler 方式

In recent years, people have adopted web bundlers-- like webpack, parcel, rollup, and more -- to manage multiple files and dependencies.近年来,人们采用了 web 打包器(如 webpack、parcel、rollup 等)来管理多个文件和依赖项。 These tools are intended to output a single web bundle and have a lot of nice, customizable features for that.这些工具旨在输出单个 Web 包,并为此提供许多不错的、可定制的功能。 They might need a bit of work to get up and running, and need to use a CommonJS plugin to get require working.他们可能需要做一些工作才能启动和运行,并且需要使用 CommonJS 插件来让require工作。 For instance, see here to get ace working with webpack.例如,请参阅此处让 ace 与 webpack 一起工作。

Do you need to bundle?需要捆绑吗?

Depending on your concerns and situation, bundling might not need be an optimization you need.根据您的顾虑和情况,捆绑可能不需要是您需要的优化。 Historically, bundling was used as a way to minimize network requests, since the number of network connections was limited, and sometimes files requested other files, leading to loading in serial.历史上,捆绑被用作最小化网络请求的一种方式,因为网络连接的数量是有限的,有时文件会请求其他文件,导致串行加载。 Many of these concerns were addressed with HTTP/2. HTTP/2 解决了其中的许多问题。 Just make sure that your web server supports HTTP/2 and that you're serving all the files on that server.只需确保您的 Web 服务器支持 HTTP/2 并且您正在为该服务器上的所有文件提供服务。 For more information about this, see this question .有关这方面的更多信息,请参阅此问题 You probably care most of how it operates in practice, so you'd probably want to benchmark it either way, but you might not be gaining much.您可能最关心它在实践中的运作方式,因此您可能希望以任何一种方式对其进行基准测试,但您可能不会获得太多收益。

We can simply use webpack to get what you're looking for我们可以简单地使用 webpack 来获取您正在寻找的内容

webpack with vanilla 带有香草的 webpack

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

You can use require and source script together,你可以一起使用requiresource script

At the first , config your webpack.config.js Webpack Docs首先,配置你的webpack.config.js Webpack Docs

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,
                },
            },
        ],
    },
};

In the second step, require the files you need第二步, require你需要的文件

// Es5
const x = require('x');
const y = require('y');

// Es6
import * as x from 'x';
import y from 'y';
import { z } from 'z';

Use the script tag instead of importing使用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>

Notice: Scripts must be executed after all注意:脚本终究要执行

You can also use the scripts you imported in the script tag in your files您还可以use the scripts您在文件imported in the script tagimported in the script tag

App.js应用程序.js

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

List the files you do not require as follows列出你不需要的文件如下

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM