具有外部JS依赖关系的Maven项目中的RequireJS编译

时间:2011-01-11 23:04:05

标签: dependencies maven javascript requirejs

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

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

我打包了第三方JavaScript库,它们作为依赖项下载,然后添加了WAR Overlay插件。

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

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

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


更新:现有POM代码段

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

所以,有些问题是:

  1. 如何为编译和WAR打包步骤提取单个压缩依赖项的不同部分?或者我是否必须创建两个zip文件,一个只有运行时的东西,另一个用于编译脚本?
  2. 我想在编译期间理想地触发exec:exec,或者如果没有,就在WAR打包之前。我该怎么做?
  3. 我实际上尝试了一些没有成功的东西,所以我希望我不会懒得发布大量的代码并等待答案:)这只是我没有完全理解Maven目标/阶段等工作。

3 个答案:

答案 0 :(得分:8)

答案 1 :(得分:6)

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

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

它应该始终附带最新版本的RequireJS,并且通过向项目添加不同的版本并在插件配置中指定它的路径来轻松覆盖它。

完全披露:我写了插件。

答案 2 :(得分:4)

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

我没有依赖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包的全部内容放在“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>

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

<强>更新

自编写此解决方案以来,我已切换到使用“java”目标而不是“exec”,因为我在通过Hudson使用RequireJS编译器的shell脚本+批处理文件时遇到了问题。我基本上运行最终的Java命令(由脚本生成),通过Rhino运行编译器。 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>