【问题标题】:Merging requirejs and plain js file together将requirejs和plain js文件合并在一起
【发布时间】:2021-12-03 09:29:04
【问题描述】:

我正在开发一个小网站,主要的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>

(真实的可见here)。

以下是未缩小的文件:

前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 代码

【问题讨论】:

  • 你已经用“目标”更新了你的问题......但是XY-problem来了。 为什么你需要这个?
  • @x00 我真的不需要它,但我很好奇。实际上,我在问自己几个问题:是否可以将这些文件捆绑在一起?将文件捆绑在一起会导致更好的缩小/压缩吗?提供来自 2 个不同域的文件的开销是多少?所以我实现了史蒂夫提供的“快速方式”解决方案,并将其部署在我的产品服务器上,根据页面速度洞察实验室数据,有一个加速。现在我将等待几周,看看现实世界的数据是否显示出相同的趋势
  • 如果你要找的话,我可以用 webpack 或 rollup 给它拍摄?
  • 将所有 3 个文件中的代码复制并粘贴到一个主 js 文件中并调用它?除非我没有完全理解你的问题

标签: javascript merge module requirejs bundle


【解决方案1】:

我有点困惑。您说您对前 3 个文件使用 requirejs,但这不是我对如何使用 requirejs 的理解。您通常会有一个主 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>

然后在 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

接下来安装uglify

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。这应该会给你一个单一的、缩小的文件 bundle.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>

【讨论】:

    【解决方案2】:

    @Booboo 的回答基本正确。但我想加我的 5 美分:

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

    【讨论】:

      【解决方案3】:

      这是一个有趣的问题,因为在 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
      

      (如果您删除\s,您可以将它们全部合并到一行。如果您知道文件以新行结尾,您也可以省略&lt;(echo)

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

      RequireJS 方式

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

      Web Bundler 方式

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

      你需要捆绑吗?

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

      【讨论】:

        【解决方案4】:

        我们可以简单地使用 webpack 来获取您要查找的内容

        webpack with vanilla

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

        【讨论】:

          【解决方案5】:

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

          类似这样的:

          bundle.js:

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

          【讨论】:

            【解决方案6】:

            你可以同时使用requiresource script

            首先,配置你的webpack.config.jsWebpack 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,
                            },
                        },
                    ],
                },
            };
            

            第二步,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 scriptsimported in the script tag

            App.js

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

            如下列出你不需要的文件

            【讨论】:

              猜你喜欢
              • 2013-03-21
              • 2014-03-06
              • 2017-10-10
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-12-21
              相关资源
              最近更新 更多