TheProjecter / wro4j

Automatically exported from code.google.com/p/wro4j
0 stars 0 forks source link

Google closure compiler complains about namespace never provided #274

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
Im trying to create minified js with google compiler. My wro.xml is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<groups xmlns="http://www.isdc.ro/wro"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.isdc.ro/wro wro.xsd">

    <group name="my-script.min">
        <js>file:src/main/closure/goog/base.js</js>
        <js>file:src/main/closure/goog/dom/dom.js</js>
        <js>file:src/main/closure/goog/array/array.js</js>
        <js>file:src/main/closure/goog/dom/tagname.js</js>
        <js>file:src/main/closure/goog/dom/classes.js</js>
        <js>file:src/main/closure/goog/math/coordinate.js</js>
        <js>file:src/main/closure/goog/math/size.js</js>
        <js>file:src/main/closure/goog/object/object.js</js>
        <js>file:src/main/closure/goog/string/string.js</js>
        <js>file:src/main/closure/goog/useragent/useragent.js</js>
        <js>file:src/main/closure/goog/asserts/asserts.js</js>
        <js>file:src/main/closure/goog/debug/error.js</js>
        <js>file:src/main/closure/goog/net/xhrio.js</js>
        <js>file:src/main/closure/goog/debug/logger.js</js>
        <js>file:src/main/closure/goog/debug/entrypointregistry.js</js>
        <js>file:src/main/closure/goog/debug/errorhandlerweakdep.js</js>
        <js>file:src/main/closure/goog/events/eventtarget.js</js>
        <js>file:src/main/closure/goog/json/json.js</js>
        <js>file:src/main/closure/goog/net/errorcode.js</js>
        <js>file:src/main/closure/goog/net/eventtype.js</js>
        <js>file:src/main/closure/goog/net/httpstatus.js</js>
        <js>file:src/main/closure/goog/net/xmlhttp.js</js>
        <js>file:src/main/closure/goog/net/xhrmonitor.js</js>
        <js>file:src/main/closure/goog/structs/structs.js</js>
        <js>file:src/main/closure/goog/structs/map.js</js>
        <js>file:src/main/closure/goog/uri/utils.js</js>
        <js>file:src/main/closure/goog/debug/logbuffer.js</js>
        <js>file:src/main/closure/goog/debug/logrecord.js</js>
        <js>file:src/main/closure/goog/disposable/disposable.js</js>
        <js>file:src/main/closure/goog/events/events.js</js>
        <js>file:src/main/closure/goog/timer/timer.js</js>
        <js>file:src/main/closure/goog/net/wrapperxmlhttpfactory.js</js>
        <js>file:src/main/closure/goog/iter/iter.js</js>
        <js>file:src/main/closure/goog/disposable/idisposable.js</js>
        <js>file:src/main/closure/goog/events/browserevent.js</js>
        <js>file:src/main/closure/goog/events/event.js</js>
        <js>file:src/main/closure/goog/events/eventwrapper.js</js>
        <js>file:src/main/closure/goog/events/pools.js</js>
        <js>file:src/main/closure/goog/net/xmlhttpfactory.js</js>
        <js>file:src/main/closure/goog/debug/debug.js</js>
        <js>file:src/main/closure/goog/structs/set.js</js>
        <js>file:src/main/closure/goog/dom/browserfeature.js</js>
        <js>file:src/main/closure/goog/reflect/reflect.js</js>
        <js>file:src/main/closure/goog/events/listener.js</js>
        <js>file:src/main/closure/goog/structs/simplepool.js</js>
        <js>file:src/main/closure/goog/useragent/jscript.js</js>
        <js>file:src/main/closure/goog/events/browserfeature.js</js>
        <js>file:src/main/closure/goog/events/eventtype.js</js>
        <js>file:src/main/closure/goog/fx/fx.js</js>
        <js>file:src/main/closure/goog/fx/dom.js</js>
        <js>file:src/main/closure/goog/fx/animation.js</js>
        <js>file:src/main/closure/goog/fx/easing.js</js>
        <js>file:src/main/closure/goog/color/color.js</js>
        <js>file:src/main/closure/goog/style/style.js</js>
        <js>file:src/main/closure/goog/color/names.js</js>
        <js>file:src/main/closure/goog/math/math.js</js>
        <js>file:src/main/closure/goog/math/box.js</js>
        <js>file:src/main/closure/goog/math/rect.js</js>

        <js>/scripts/my-script.js</js>
    </group>

</groups>

But the compiler says:

com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: /scripts/my-script.js:1: ERROR - required "goog.dom" namespace never 
provided goog.require('goog.dom');
... 
etc

Question 1: Is this a bug or I missunderstand how wro4j works?
Question 2: Where to place the closure library files so the compiler will pick 
them up. Where is this configured?

Note: gtrak asked similiar question on stackoverflow.com:
http://stackoverflow.com/questions/6807624/how-do-you-use-wro4j-together-with-th
e-closure-library-and-compiler

Original issue reported on code.google.com by pohorele...@gmail.com on 10 Aug 2011 at 6:11

GoogleCodeExporter commented 8 years ago
Can you provide the minimum wro.xml configuration with which I can reproduce 
the bug. If you can, send me the js files (as attachment or a link to a public 
repository).

Are you using the wro4j maven plugin or the filter? 

The google closure can be used as a pre processor or a post processor. This may 
be important in this context. You can find more about this on wiki pages.

Original comment by alex.obj...@gmail.com on 10 Aug 2011 at 6:37

GoogleCodeExporter commented 8 years ago
1) Actually this is the minimum wro4j.xml configuration. In project I use only 
Dom, XhrIo and Animations, but these javascripts has other dependencies listed 
in wro.xml

2) I use maven plugin version 1.3.8

3) I use it as a pre processor

Note: The GoogleClosureCompressorProcessor class does not set 
manageClosureDependencies to true (The default is set to false, so compiler 
does not automatically sort dependencies). After small modifiyng processor I 
used it in factory:

public class EnhancedGoogleAdvancedStandaloneManagerFactory
        extends DefaultStandaloneContextAwareManagerFactory
{
    /**
     * {@inheritDoc}
     */
    @Override
    protected ProcessorsFactory newProcessorsFactory()
    {
        final SimpleProcessorsFactory factory = new SimpleProcessorsFactory();
        factory.addPreProcessor( new BomStripperPreProcessor() );
        factory.addPreProcessor( new CssImportPreProcessor() );
        factory.addPreProcessor( new CssUrlRewritingProcessor() );
        factory.addPreProcessor( new SemicolonAppenderPreProcessor() );
        factory.addPreProcessor( new EnhancedGoogleClosureCompressorProcessor() );
        factory.addPreProcessor( new JawrCssMinifierProcessor() );

        factory.addPostProcessor( new CssVariablesProcessor() );
        return factory;
    }
}

Compressor:

@Minimize
@SupportedResourceType( ResourceType.JS)
public class EnhancedGoogleClosureCompressorProcessor
        extends GoogleClosureCompressorProcessor
{
    /**
     * {@link CompilationLevel} to use for compression.
     */
    private final CompilationLevel compilationLevel = CompilationLevel.ADVANCED_OPTIMIZATIONS;

    /**
     * {@inheritDoc}
     */
    public void process( final Resource resource, final Reader reader, final Writer writer )
            throws IOException
    {
        final String content = IOUtils.toString( reader );
        try
        {
            com.google.javascript.jscomp.Compiler.setLoggingLevel( Level.SEVERE );
            final Compiler compiler = new Compiler();
            final CompilerOptions options = new CompilerOptions();
            compilationLevel.setOptionsForCompilationLevel( options );
            //This is important in order to avoid INTERNAL_ERROR (@see https://groups.google.com/forum/#!topic/closure-compiler-discuss/TDPtHU503Xk}
            options.foldConstants = false;
            options.setManageClosureDependencies( true ); // this must me set to true otherwise compiler will not automatically sort dependencies which will cause more exceptions of type 'required "goog.dom" namespace never provided goog.require...'
            //make it play nice with GAE
            compiler.disableThreads();
            compiler.initOptions( options );
            /**
             * According to John Lenz from the Closure Compiler project, if you are using the Compiler API directly, you
             * should specify a CodingConvention. {@link http://code.google.com/p/wro4j/issues/detail?id=155}
             */
            options.setCodingConvention( new DefaultCodingConvention() );
            //set it to warning, otherwise compiler will fail
            options.setWarningLevel( DiagnosticGroups.CHECK_VARIABLES,
                    CheckLevel.WARNING );

            final JSSourceFile extern = JSSourceFile.fromCode( "externs.js", "" );
            final String fileName = resource == null ? "wro4j-processed-file.js" : resource.getUri();
            final JSSourceFile input = JSSourceFile.fromInputStream( fileName,
                    new ByteArrayInputStream( content.getBytes( Context.get().getConfig().getEncoding() ) ) );
            final Result result = compiler.compile( extern, input, options );
            if ( result.success )
            {
                writer.write( compiler.toSource() );
            }
            else
            {
                writer.write( content );
            }
        }
        finally
        {
            reader.close();
            writer.close();
        }
    }

}

Original comment by pohorele...@gmail.com on 10 Aug 2011 at 7:34

GoogleCodeExporter commented 8 years ago
I'm not sure I understand, does your change solves the problem?

Original comment by alex.obj...@gmail.com on 10 Aug 2011 at 8:05

GoogleCodeExporter commented 8 years ago
No, it does not.. It just fixed the problem with dependencies in closure 
library, but not with my javascript files.

So if manageClosureDependencies is set to false, compiler complains in closure 
library javascript files and in my javascript files as well. But if I set it to 
true compiler complains only to my javascript files.

Example of my-script.js:

goog.require( 'goog.dom' ); // compiler complains here..
goog.require( 'goog.events' ); // ... and here

goog.dom.createDom( 'header' );
goog.dom.appendChild( document.body, element );

P.S.: When I tried to run compiler.jar I did not see these exceptions so I 
thing there must be some hidden bug in wro plugin.

Original comment by pohorele...@gmail.com on 10 Aug 2011 at 8:15

GoogleCodeExporter commented 8 years ago
Could you try using google closure as a post processor? I'll take a look on 
this problem tomorrow.

Original comment by alex.obj...@gmail.com on 10 Aug 2011 at 8:57

GoogleCodeExporter commented 8 years ago
When I use it as a post processor compiler shows this exception:
SEVERE: ERROR - Circular dependency detected: goog.fx.dom.FadeIn -> 
goog.fx.dom.FadeIn

Also minimized file was not minimized at all. Compiler only put togeteher all 
scripts without minifying.

Original comment by pohorele...@gmail.com on 11 Aug 2011 at 8:17

GoogleCodeExporter commented 8 years ago
That is an expected behavior. When google closure processing fails, wro4j 
leaves it unchanged. However the circular dependency is something you should be 
able to fix. Is the reference to goog.fx.dom.FadeIn included twice in the group?

Original comment by alex.obj...@gmail.com on 11 Aug 2011 at 8:22

GoogleCodeExporter commented 8 years ago
I do not think so.

When I use this configuration:
<group name="my-script.min">
  <js>/scripts/my-script.js</js>
</group>
Compiler says:
11.8.2011 11:01:31 com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: wro4j-processed-file.js:14: ERROR - required "goog.dom" namespace never 
provided
Lang.add("button.review", "Prehľad objednávky");goog.require( 'goog.dom' );
                                                            ^

11.8.2011 11:01:31 com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: wro4j-processed-file.js:15: ERROR - required "goog.events" namespace 
never provided
goog.require( 'goog.events' );
            ^

11.8.2011 11:01:31 com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: wro4j-processed-file.js:277: ERROR - required "goog.net.XhrIo" 
namespace never provided
};goog.require( 'goog.net.XhrIo' );
              ^

11.8.2011 11:01:31 com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: wro4j-processed-file.js:278: ERROR - required "goog.fx" namespace never 
provided
goog.require( 'goog.fx' );
            ^

11.8.2011 11:01:31 com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: wro4j-processed-file.js:279: ERROR - required "goog.fx.dom" namespace 
never provided
goog.require( 'goog.fx.dom' );
            ^

But if I add goog.dom:
<group name="my-script.min">
  <js>/scripts/my-script.js</js>
  <js>file:src/main/closure/goog/dom/dom.js</js>
</group>
Compiler says:
11.8.2011 11:02:53 com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: ERROR - Circular dependency detected: goog.dom -> goog.dom

So I have no idea where is the problem.

Original comment by pohorele...@gmail.com on 11 Aug 2011 at 9:03

GoogleCodeExporter commented 8 years ago
Interesting...
What happens if you try:
 options.setManageClosureDependencies( false ); 

Original comment by alex.obj...@gmail.com on 11 Aug 2011 at 9:19

GoogleCodeExporter commented 8 years ago

Original comment by alex.obj...@gmail.com on 11 Aug 2011 at 9:19

GoogleCodeExporter commented 8 years ago
I will try to reproduce this problem myself. Also, I think I should understand 
the google closure internals in order to be able to fix it. 

wro4j does nothing but apply some processing on a js resource.. most probably 
there is a misconfiguration of GoogleClosureCompiler or something else I've 
missed. I'll let you know about any updates.

Original comment by alex.obj...@gmail.com on 11 Aug 2011 at 9:22

GoogleCodeExporter commented 8 years ago
If I set it to false nothing change:

11.8.2011 12:03:05 com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: wro4j-processed-file.js:1477: ERROR - required "goog.array" namespace 
not provided yet
goog.require('goog.array');
            ^

11.8.2011 12:03:05 com.google.javascript.jscomp.LoggerErrorManager println
SEVERE: wro4j-processed-file.js:1478: ERROR - required 
"goog.dom.BrowserFeature" namespace not provided yet
goog.require('goog.dom.BrowserFeature');        

---

Ok, I will wait for any updtes..Thank you for help.

Original comment by pohorele...@gmail.com on 11 Aug 2011 at 10:05

GoogleCodeExporter commented 8 years ago

Original comment by alex.obj...@gmail.com on 11 Aug 2011 at 7:47

GoogleCodeExporter commented 8 years ago
Apparently google closure compiler does some magic under the hood, using the 
goog.require & goog.provide for dependency management. This is, at least on the 
first glance, not compatible with the way wro4j works. 

The quick workaround is to remove all goog.require & goog.provide statements 
from the code and allow wro4j to manage dependencies in wro.xml file. It is 
possible to automate by creating a specialized processor which removes all 
these statements from js code.

This can be a temporary solution, until a better approach is found. I have to 
look into compiler internals to see if what it does, can be reused. But I 
wouldn't like to pollute wro4j code with compiler specific logic. The idea is 
to keep it as simple as possible. 

In conclusion:
1) Manage dependencies in your wro.xml file
2) Do not use goog.require & goog.provide

Please, let me know what do you think.

Original comment by alex.obj...@gmail.com on 11 Aug 2011 at 8:39

GoogleCodeExporter commented 8 years ago
I am not sure if I understand it correctly: Should I remove all goog.require 
and goog.provide form my javascripts and from closure library javascript as 
well?

Because in that case I do not really like it at all. Thats a huge hack against 
closure compiler, so I would rather use command line to create minimized 
javascripts and automate it with maven or ant.

Original comment by pohorele...@gmail.com on 12 Aug 2011 at 7:48

GoogleCodeExporter commented 8 years ago
I'm not saying this is a long term solution. I will do further investigations. 

Actually you can use CompilationLevel.WHITESPACE_ONLY (which won't complain) 
and no other hacks are required. If you want to use more advanced compilation 
levels and you have goog.require or goog.provide statements which are used by 
google closure compiler to do some internal magic, then there is no quick 
solution other than remove these statements (manually or automatically using a 
specialized processor). 

The problem with the google closure compiler approach is that it is configured 
to consume only files, while wro4j use a higher level abstraction of reading 
resources from a stream. I'm not sure yet how I can tweak google closure 
compiler to work properly in this context. But this is something that requires 
some investigations. I would appreciate any help or hints from peoples who have 
some experience with google closure. I will invest some time for this issue in 
the future, but cannot promise that it will be available very soon.

Original comment by alex.obj...@gmail.com on 12 Aug 2011 at 8:00

GoogleCodeExporter commented 8 years ago
If google closure is against concept of wro4j maybe you should remove it from 
wr04j and create google closure extension. 

Note: I have tried to use google Compiler api but it does not worked properly, 
so I ended with Simple class which executes java -jar compiler.jar... Also I 
have searched for some examples about how you should use Compiler api but 
without no result. It seems that it is not documented very well yet ( Or I am 
blind :) ).

Original comment by pohorele...@gmail.com on 15 Aug 2011 at 11:41

GoogleCodeExporter commented 8 years ago
Google closure, from wro4j point of view, is just another minifier like 
(PackerJs, Dojo Shrinksafe or UglifyJs). Unfortunately, google closure is the 
only one who requires some special treatment when using it. Ideally, using it 
should be as simple as: 

Closure.minify(stream, options); 

I think it still can be used in wro4j, because in most cases goog.require & 
goog.provide is not used. Most of the projects relies on classic js library 
(jquery, prototype) and a lot of custom libraries. Also, using WHITESPACE_ONLY 
is a viable option. You can also always switch from one minifier to another 
(uglifyJs can be better than google closure in some situations).

wro4j doesn't compete with google closure, rather it tries to add all known 
similar tools under a single umbrella and simplify the way you can use these in 
your project(s). It can be easily used as a build tool or code analysis tool. 
Of course, if you have good reason of using google closure and it does exactly 
what you need, then using it is the best way to go. This is the nice thing 
about open source, you choose the best tool which suites you based on your 
needs.

I understand the current limitation, but unless get some help or contributions, 
there is no fast or easy way to fix it. I'm always open for fair suggestions or 
patches if you have any.

Thank you!

Original comment by alex.obj...@gmail.com on 15 Aug 2011 at 11:56