GithubHelp home page GithubHelp logo

gaozq / closure-compiler-maven-plugin Goto Github PK

View Code? Open in Web Editor NEW

This project forked from blutorange/closure-compiler-maven-plugin

0.0 0.0 0.0 2.93 MB

Combine and minimize JavaScript with Closure Compiler.

Home Page: http://blutorange.github.com/closure-compiler-maven-plugin

License: Apache License 2.0

JavaScript 16.66% Java 83.34%

closure-compiler-maven-plugin's Introduction

Closure Compiler Maven Plugin

Forked from Minify Maven Plugin. That project seems to be inactive. In line with the principle of single responsibility, this fork is meant only for processing JavaScript files. The YUI Compressor is dead, so what remains is a maven plugin for Google Closure Compiler. I found some plugins for the closure compiler, but found them all to be lacking - by not having a recent version of closure compile, not exposing many of its options or not handling files well. So I decided to fork the excellent Minify Maven Plugin as a base for a closure compiler maven plugin.

This plugin combines and minimizes JavaScript files. It produces a merged and a minified version.

Requires at least Java 11.

Usage

Configure your project's pom.xml to run the plugin during the project's build cycle.

<build>
  
  <!-- Exclude the sources in "src/main/resources/includes" -->
  <!-- Include the transpiled files in "target/generated-resources/includes" -->
  <resources>
    <resource>
      <directory>${project.basedir}/src/main/resources</directory>
      <excludes>
        <exclude>includes/**/*.js</exclude>
      </excludes>
      </resource>
      <resource>
        <directory>${project.basedir}/target/generated-resources</directory>
      </resource>
  </resources>
  
  <!-- Transpiled all sources from               -->
  <!--     "src/main/resources/includes"         -->
  <!--  to                                       -->
  <!--     "target/generated-resources/includes" -->
  <plugins>
    <plugin>
      <groupId>com.github.blutorange</groupId>
      <artifactId>closure-compiler-maven-plugin</artifactId>
      <version>2.22.0</version>
      <configuration>
        <!-- Base configuration for all executions (bundles) -->
        <baseSourceDir>${project.basedir}/src/main/resources</baseSourceDir>
        <baseTargetDir>${project.build.directory}/generated-resources</baseTargetDir>
      </configuration>
      <executions>
        <!-- Process all files in the "includes" directory individually-->
        <execution>
          <id>default-minify</id>
          <configuration>
            <encoding>UTF-8</encoding>
            <sourceDir>includes</sourceDir>
            <targetDir>includes</targetDir>
            <includes>
              <include>**/*.js</include>
            </includes>
            <skipMerge>true</skipMerge>
            <closureLanguageOut>ECMASCRIPT5</closureLanguageOut>
          </configuration>
          <goals>
            <goal>minify</goal>
          </goals>
          <phase>generate-resources</phase>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Documentation

For more information, check the documentation or the test projects.

Paths, directories and files

To process our files, we need to know where they are located and where we want the output to go to. This sound simple, but it gets more complicated as you also want files to be ordered the right way, use wild cards, have relative paths, create source maps etc. This is short explanation of how file handling works with this plugin.

Any transpilation process consists of two main ingredients: The source (or input) files; and the target (or output) files. First we need to establish the base directory, which needs to be an absolute path on the file system:

  • baseSourceDir: The absolute path of the direcotry with the input files. Usually the source file of our project, eg. ${project.basedir}/src/webapp
  • baseTargetDir: The absolute path of the directory with the output files. Usually the target directory of our maven project, eg. ${project.basedir}/target/generated-resources

For larger projects, we may want to run closure compiler multiple times on different sets of files. We can do this with multiple executions of this plugin. But as we are still working within the same project, we don't want to set the absolute path to our project each and every time. For each execution, we only want to specify a relative path:

  • sourceDir: The path to the directory with the source files, relative to the baseSourceDir.
  • targetDir: The path to the directory with the source files, relative to the baseTargetDir.

Next, we want to specify some actual files to process:

  • includes: List of files to include. This is relative to the sourceDir. Wildcards are allowed. Eg. **/*.js
  • excludes: List of files to exclude. This is relative to the sourceDir. Wildcards are allowed. Eg. do_not_process.js

So how are these source files ordered? We could take all includes and excludes, figure out all matching files, and sort them alphabetically. But this means we could not specify the order of files manually if we ever needed it. On the other hand, when we use wild cards to specify a set of files, we probably want these to be sorted. To get the best of both world, this plugin orders files like this:

  • For each <include>, find all files matching the wildcard pattern (observing the <excludes>).
  • For each <include>, sort the matching files alphabetically.
  • Then add the matching files for each include in the order the <include>s were specified.

Another thing to mention here is how the files are passed to closure compiler. Closure compiler never reads files from the files system itself. When ES modules are used, it does not look in the file system for the imported files. It expects that we give it all the inpt files it needs. To pass a source file to closure compiler, we need to give it the content of the file, as well as a (possibly relative) path to the file. If we pass the wrong path, closure compiler may not be able to resolve reference between files. This plugin always uses the path of a source file on the file system, relative to the sourceDir. So if we set the baseSourceDir to /home/john/git/project/src/webapp and sourceDir to js; and have a file at /home/john/git/project/src/webapp/js/logic/model.js: the file is passed to closure compiler with the file name logic/model.js By doing it this way, we also get closure compiler to "just work" with node.js projects: We just need to set the source directory to the main directory of the node project (with the node_modules folder) and set closureModuleResolution to NODE.

Finally, we want to tell the plugin where to place the output file(s). There are two cases here, depending on whether we want to merge all input files into once large file; or just process each file separately and place these files into the target directory:

  • skipMerge: If true, process each file individually. Otherwise, merge all source files.
  • outputFilename: The location of the output file, relative to the targetDir. When we merge all files, we usually want to specify an fixed name, eg. bundle.min.js. When we skip the merge process, we can use variables to customize the directory and file name. The default here is #{path}/#{basename}.min.#{extension}, which uses the original filename with a .min before the extension, and preserves the directory structure of the input files. See the linked documentation for more details.

As a bonus, we may sometimes want to create a source map as well. The easiest and quickest way to get working source maps is to:

This includes the entire source map as well as the original source file content in the minified file itself. As soon as the browser loads the minfied file, it's got everything it needs and the source map feature just works. Now in case we do not like our source maps being that large, we need to keep the source map as a separate file. That involves several paths:

  • The path from the minified file to the source map (so the browser can find it)
  • The path from the source map to the minified file (which is part of the source map)
  • The path from the source map to the original source files (so the browser can find them)

Before we can worry about that, we need to specify where to put the generated source map:

  • closureSourceMapName: Path and file name of the source map, relative to the directory of the outputFilename.

Now we can worry about the paths mentioned above. The first two are easy: we know the location of the minified file and the source map files, so we just use the corresponding relative paths. And normally, both the minified file and the source map are put inside the same directory.

The last one - the path from the source map to the original source files - is not quite as easy. The source map is generated by closure compiler and by default, closure compiler just uses the name of the source file as it was passed to it: that is, relative to the sourceDir This usually won't work, because the source map is placed in the targetDir, so the relative path won't be correct. Fortunately, closure compiler offer an option to remap the location of (path to the) source files when it creates the source map. By default, this plugin sets this option so that the paths are correct with respect to the underlying file system. So for example, if we set

  • the source directory to /home/john/git/project/src/webapp
  • the target directory to /home/john/git/project/target/generated-sources
  • the includes to js/index.js
  • the output file name to bundle.min.js
  • the source map file name to bundle.min.map.js

Then we get the two output files

  • /home/john/git/project/target/generated-sources/bundle.min.js and
  • /home/john/git/project/target/generated-sources/bundle.min.map.js

The source map bundle.min.map.js now references the source files as ../../src/webapp/js/index.js. When your project directory structure resembles your directory structure on the server, then by default, every will just work. If the directory structure is diffrent, closure compiler offers the option source_map_location_mapping. For this plugin, this is set with the option:

  • closureSourceMapLocationMappings: When the file name of a source file contains the given prefix, it is replaced with the specified replacement. Here the file name is as it was passed to closure compiler, ie. relative to the sourceDir

For the example above, this means that the source file name would be js/index.js. We could now set this option to replace js/ with https://example.com/sources/. Now the source map contains a reference to the source file as https://example.com/sources/index.js.

Build site

  • Edit files in /src/site
  • mvn clean plugin:report site
    • You can check out the locally rendered rendered site in target/site/index.html.
  • To upload to github, add the profile site
    • mvn clean plugin:report site -P site

Release

  • mvn versions:display-dependency-updates
  • Update version in pom.xml and src/test/resources/projects/parent/pom.xml.
  • Update version in README.md.
  • Update CHANGELOG.md
  • Generate site, check links
  • Upload site to github (see above)
  • Upload source to github
  • mvn clean install
  • mvn -P release deploy

Test

The test projects need a built version of the plugin, so make a full local build first:

mvn clean install -DskipTests

You may need to run an install on a test project first to download the required dependencies:

cd src/test/resources/projects/minimal/
mvn install
cd ../../../../../

Now test away

mvn clean package test

To run only a single test for debugging, use

# nameOfTestMethod is one of the methods annotated with @Test in MinifyMojoTest
# For example: testOutputFilename
mvn test -Dtest=MinifyMojoTest#nameOfTestMethod

To add a new test, go to src/test/resources/projects/, copy one of the test projects as a base (except parent). Open the pom.xml and change the artifactId to a new name. Edit the closure compiler configuration as necessary. Add input JavaScript files to the directory test and the expected output files to the directory expected. Finally open MinifyMojoTest and add a new test method:

  @Test
  public void testMyproject() throws Exception {
    runMinify("myproject");
  }

License

This distribution is licensed under the terms of the Apache License, Version 2.0 (see LICENSE.txt).

closure-compiler-maven-plugin's People

Contributors

samaxes avatar blutorange avatar awa-xima avatar mbme avatar sps avatar gabrielsjoberg avatar krudolph avatar afaust avatar andreasrosdal avatar dcendents avatar hboylan avatar madisparn avatar samcday avatar i045053 avatar dms-it avatar spodgurskiy avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.