javascript Maven 项目中的RequireJS 编译与外部JS 依赖项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4663686/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 14:28:29  来源:igfitidea点击:

RequireJS Compilation in Maven project with external JS dependencies

dependenciesmavenjavascriptrequirejs

提问by Ates Goral

I have a web project that's built with Maven and I'm trying to figure out the best way to compile the JavaScript files with the RequireJS compiler (this question could apply to any compiler/minifier as well).

我有一个使用 Maven 构建的 Web 项目,我正在尝试找出使用 RequireJS 编译器编译 JavaScript 文件的最佳方法(这个问题也适用于任何编译器/压缩器)。

I have a setup that works, but it needs improvement:

我有一个有效的设置,但需要改进:

I've packaged the 3rd party JavaScript libraries and they are being downloaded as dependencies and then added with the WAR Overlay plugin.

我已经打包了第 3 方 JavaScript 库,并将它们作为依赖项下载,然后与 WAR Overlay 插件一起添加。

I have an Exec plugin task that runs the RequireJS compiler inside the targetdirectory. I currently manually run exec:execafter the package target runs (and therefore the WAR contents are placed in the target directory).

我有一个 Exec 插件任务,它在目标目录中运行 RequireJS 编译器。我目前exec:exec在包目标运行后手动运行(因此 WAR 内容放置在目标目录中)。

What I would like instead is to make JS compilation part of main (Java) compilation. The JS compiler itself (Require JS) is downloaded as a dependency during the WAR overlay phase which happens after compilation. So, I need the Require JS files to be downloaded and unpacked and I need to run the JS compilation using those files, before/during/after Java compilation.

我想要的是使 JS 编译成为 main (Java) 编译的一部分。JS 编译器本身(需要 JS)在编译后发生的 WAR 覆盖阶段作为依赖项下载。因此,我需要下载和解压 Require JS 文件,并且需要在 Java 编译之前/期间/之后使用这些文件运行 JS 编译。

I'm sure there could be several ways to achieve this. I'm looking for the most elegant solution.

我相信可以有多种方法来实现这一目标。我正在寻找最优雅的解决方案。



Update: Existing POM snippets

更新:现有的 POM 片段

I have JavaScript dependencies which I have zipped and added to our repository manager:

我有 JavaScript 依赖项,我已将其压缩并添加到我们的存储库管理器中:

    <dependency>
        <groupId>org.requirejs</groupId>
        <artifactId>requirejs</artifactId>
        <version>0.22.0</version>
        <classifier>repackaged</classifier>
        <type>zip</type>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>com.jqueryui</groupId>
        <artifactId>jquery-ui</artifactId>
        <version>1.8.7</version>
        <classifier>repackaged</classifier>
        <type>zip</type>
        <scope>runtime</scope>
    </dependency>

Take note that RequireJS itself (which is required for the compilation of the rest of libraries) is also loaded as an external dependency. So the first thing is, I need this dependency to be downloaded and unzipped before I can commence with RequireJS compilation.

请注意,RequireJS 本身(编译其余库所需)也作为外部依赖项加载。所以第一件事是,在开始 RequireJS 编译之前,我需要下载并解压缩这个依赖项。

These dependencies are being added to the WAR using the WAR Overlay plugin:

使用 WAR Overlay 插件将这些依赖项添加到 WAR 中:

        <plugin>
            <artifactId>maven-war-plugin</artifactId>
            <configuration>
                <overlays>
                    <overlay>
                        <groupId>org.requirejs</groupId>
                        <artifactId>requirejs</artifactId>
                        <classifier>repackaged</classifier>
                        <type>zip</type>
                        <targetPath>lib</targetPath>
                        <includes>
                            <include>requirejs/require.js</include>
                            <include>requirejs/require/*</include>
                            <include>requirejs/build/**</include>
                        </includes>
                    </overlay>
                    <overlay>
                        <groupId>com.jqueryui</groupId>
                        <artifactId>jquery-ui</artifactId>
                        <classifier>repackaged</classifier>
                        <type>zip</type>
                        <targetPath>lib</targetPath>
                    </overlay>
                </overlays>
            </configuration>
        </plugin>

Even though I don't need requirejs/build/**to end up in the WAR, I'm including it as part of the overlay to get the unzipped RequireJS build scripts, simply because I haven't figured out a better way.

尽管我不需要requirejs/build/**在 WAR 中结束,但我将它作为覆盖的一部分来获取解压缩的 RequireJS 构建脚本,这仅仅是因为我还没有想出更好的方法。

Then I have a Exec plugin task that performs the compilation. But note that this task hasn't been added to the normal compilation work flow: I have to manually invoke it with mvn exec:execafterthe WAR packaging is done:

然后我有一个执行编译的 Exec 插件任务。但请注意,此任务尚未添加到正常的编译工作流程中:我必须在 WAR 打包完成mvn exec:exec手动调用它:

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>exec</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <executable>lib/requirejs/build/build.bat</executable>
                <workingDirectory>${project.build.directory}/${project.artifactId}</workingDirectory>
                <arguments>
                    <argument>name=bootstrap</argument>
                    <argument>out=combined.js</argument>
                    <argument>baseUrl=scripts</argument>
                    <argument>optimize=closure</argument>
                    <argument>excludeShallow=plugins/manifest</argument>
                </arguments>
            </configuration>
        </plugin>

So, some questions are:

所以,一些问题是:

  1. How can I extract different portions of a single zipped dependency for the compilation and WAR packaging steps? Or do I have to create two zip files, one with just the runtime stuff and the other for compilations scripts?
  2. I would like to trigger exec:execideally during compilation, or if not, just prior to WAR packaging. How do I do that?
  1. 如何为编译和 WAR 打包步骤提取单个压缩依赖项的不同部分?或者我是否必须创建两个 zip 文件,一个只包含运行时内容,另一个用于编译脚本?
  2. 我想exec:exec在编译期间理想地触发,或者如果没有,就在 WAR 打包之前触发。我怎么做?

I have actually tried a bunch off stuff without success, so I hope I don't appear as lazily posting a huge chunk of code and waiting for answers :) It's just that I haven't quite wrapped my mind around how Maven targets/phases etc. work yet.

我实际上尝试了很多东西但没有成功,所以我希望我不会显得懒惰地发布大量代码并等待答案:) 只是我还没有完全考虑 Maven 的目标/阶段等工作呢。

采纳答案by Ates Goral

I've come up with the following solution that works for me:

我想出了以下对我有用的解决方案:

Instead of depending on the WAR overlay for the unpacking of the RequireJS files, I explicitly unpack them using the Dependency plugin:

我没有依赖 WAR 覆盖来解压 RequireJS 文件,而是使用 Dependency 插件明确地解压它们:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
      <execution>
        <phase>compile</phase>
        <goals>
          <goal>unpack</goal>
        </goals>
        <configuration>
          <artifactItems>
            <artifactItem>
              <groupId>org.requirejs</groupId>
              <artifactId>requirejs</artifactId>
              <version>0.22.0</version>
              <type>zip</type>
              <classifier>repackaged</classifier>
              <overWrite>true</overWrite>
            </artifactItem>
          </artifactItems>
        </configuration>
      </execution>
    </executions>
  </plugin>

The phase is set to "compile". This allows me to have the entire contents of the RequireJS package under the "dependency" folder, during compilation. So, the next thing I have is:

阶段设置为“编译”。这允许我在编译期间将 RequireJS 包的全部内容放在“dependency”文件夹下。所以,我接下来要做的是:

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.1</version>
        <executions>
          <execution>
            <phase>compile</phase>
            <goals>
              <goal>exec</goal>
            </goals>
            <configuration>
              <executable>
              ${project.build.directory}/dependency/requirejs/build/build.bat</executable>
              <workingDirectory>
              ${basedir}/src/main/webapp</workingDirectory>
              <arguments>
                <argument>name=bootstrap</argument>
                <argument>out=scripts/compiled.js</argument>
                <argument>baseUrl=scripts</argument>
                <argument>optimize=closure</argument>
                <argument>
                excludeShallow=plugins/manifest</argument>
              </arguments>
            </configuration>
          </execution>
        </executions>
      </plugin>

This triggers RequireJS compilation inside the "dependency" folder, without touching either my source directory or the WAR directory. I then continue using the WAR overlay plugin to cherry pick the RequireJS files that want to go into the WAR.

这会在“dependency”文件夹中触发 RequireJS 编译,而不会触及我的源目录或 WAR 目录。然后我继续使用 WAR 覆盖插件来挑选想要进入 WAR 的 RequireJS 文件。

Update

更新

Since writing this solution, I've switched to using the "java" goal instead of "exec" because I had problems with using the RequireJS compiler's shell script + batch file through Hudson. I'm basically running the final Java command (generated by the scripts) that run the compiler through Rhino. The Node solution would be slightly different. For RequireJS 0.23.0, it goes something like this:

自从编写此解决方案以来,我已切换到使用“java”目标而不是“exec”,因为我在通过 Hudson 使用 RequireJS 编译器的 shell 脚本 + 批处理文件时遇到了问题。我基本上是在运行通过 Rhino 运行编译器的最终 Java 命令(由脚本生成)。Node 解决方案会略有不同。对于 RequireJS 0.23.0,它是这样的:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.1</version>
    <executions>
        <execution>
            <id>compile-js</id>
            <phase>compile</phase>
            <goals>
                <goal>exec</goal>
            </goals>
            <configuration>
                <executable>java</executable>
                <workingDirectory>${basedir}/src/main/webapp</workingDirectory>
                <arguments>
                    <argument>-classpath</argument>
                    <!--argument>${project.build.directory}/dependency/requirejs/build/lib/rhino/js.jar${path.separator}${project.build.directory}/dependency/requirejs/build/lib/closure/compiler.jar</argument -->
                    <argument>${project.build.directory}/dependency/requirejs/build/lib/rhino/js.jar</argument>
                    <argument>org.mozilla.javascript.tools.shell.Main</argument>
                    <argument>${project.build.directory}/dependency/requirejs/bin/x.js</argument>
                    <argument>${project.build.directory}/dependency/requirejs/bin/</argument>
                    <argument>${project.build.directory}/dependency/requirejs/build/build.js</argument>
                    <argument>name=bootstrap</argument>
                    <argument>out=scripts/compiled.js</argument>
                    <argument>baseUrl=scripts</argument>
                    <argument>optimize=none</argument>
                </arguments>
            </configuration>
        </execution>
    </executions>
</plugin>

回答by Matt Cheely

There's a maven plugin specifically targeted for RequireJS optimization at:

有一个专门针对 RequireJS 优化的 Maven 插件,位于:

https://github.com/mcheely/requirejs-maven-plugin

https://github.com/mcheely/requirejs-maven-plugin

It should always ship with a recent version of RequireJS, and it's pretty easy to override that by adding a different version to your project, and specifying it's path in the plugin config.

它应该始终与最新版本的 RequireJS 一起提供,通过向项目添加不同版本并在插件配置中指定它的路径,可以很容易地覆盖它。

Full disclosure: I wrote the plugin.

完全披露:我编写了插件。