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

Posted

技术标签:

【中文标题】Maven项目中的RequireJS编译与外部JS依赖【英文标题】:RequireJS Compilation in Maven project with external JS dependencies 【发布时间】:2011-06-07 12:20:06 【问题描述】:

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

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

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

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

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

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


更新:现有的 POM sn-ps

我已经压缩并添加到我们的存储库管理器中的 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>

请注意,RequireJS 本身(编译其余库所必需的)也作为外部依赖项加载。所以第一件事是,我需要先下载并解压缩此依赖项,然后才能开始 RequireJS 编译。

这些依赖项正在使用 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>

尽管我不需要requirejs/build/** 最终进入 WAR,但我还是将它作为覆盖的一部分来获取解压缩的 RequireJS 构建脚本,只是因为我还没有找到更好的方法。

然后我有一个执行编译的 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>

所以,有些问题是:

    如何为编译和 WAR 打包步骤提取单个压缩依赖项的不同部分?还是我必须创建两个 zip 文件,一个仅包含运行时内容,另一个用于编译脚本? 我希望在编译期间触发exec:exec,如果不是,则在WAR 打包之前触发。我该怎么做?

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

【问题讨论】:

或许你可以发布相关的pom sn-p? 【参考方案1】:

我想出了以下适合我的解决方案:

我没有依赖 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>

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

      <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>

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

更新

自从编写此解决方案以来,我已经切换到使用“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>

【讨论】:

这会尝试运行节点,因此在执行编译器时会收到错误消息。 Node 不应该是 requirejs 编译器的要求,不是吗? @adam:这是使用 RequireJS 0.22.0。你用 0.23.0 试过了吗?两者的构建脚本有很大不同。 是的,我使用的是 0.23.0,它在 build.bat 或它执行的任何 .bat 中执行节点命令【参考方案2】:

https://github.com/jakewins/requirejs-maven

【讨论】:

我已将其移至 github.com/jakewins/brew,这增加了对编译 coffeescript 和 haml 模板的支持。 brew 插件有一些在 requirejs-maven 中不可用的错误修复。 Brew 仍然不稳定,但正在积极开发并用于生产。【参考方案3】:

有一个专门针对 RequireJS 优化的 maven 插件:

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

它应该始终随最新版本的 RequireJS 一起提供,并且通过向您的项目添加不同版本并在插件配置中指定它的路径来覆盖它非常容易。

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

【讨论】:

如果项目是独立的,这很好用,但如果我们通过 maven-war-plugin 覆盖(根据 OP 的问题)拉入东西,它似乎不起作用 - 是吗?

以上是关于Maven项目中的RequireJS编译与外部JS依赖的主要内容,如果未能解决你的问题,请参考以下文章

优化 RequireJS 项目(合并与压缩) 已翻译100%

使用maven结合requirejs管理前端脚本

将 JSLint/Hint 与 requirejs 一起使用

如何从丑化/优化中排除某些 requireJS 文件

项目总结二:模块管理之requireJS

maven 常用命令