开发者

Use obfuscated CSS name from ClientBundle in down stream css

I've got a library with some CSS, and a depending project that expands on the CSS. I'm trying to move both of them to ClientBundle.

Currently, library.css is

.smallWindow { min-width: 10px; outline: none; }

And depProject.css is

.sectionA .smallWindow { color: blue; }

I moved library.css and depProject.css into Client开发者_开发技巧Bundles (LibraryBundle and DepProjectBundle) in their respective projects, but had to mark smallWindow as external in both. Is there a way to link smallWindow in depProject.css to smallWindow in library.css and still have smallWindow be obfuscated?

I'm hoping that instead of marking @external .smallWindow I could leave it alone in library.css, and put something like @replaceWithObfuscated smallWindow DepProjectBundle.css.smallWindow at the top of depProject.css


The annotation is called @external for a reason :) It's for external classes, whose names we can't control - this fits your situation. It so happens that your external project is also a GWT one, but that doesn't matter - unless you compile both projects at the same time, I don't see any (easy and non-hackish) way of (automagically) linking the obfuscated class name from LibraryBundle to DepProjectBundle.

<tech (?) rant>
ClientBundle does all it's work at compile time - it knows everything about the CSS at that point and, for example, can create non-clashing class names for all the class names included in UiBinder templates (the <ui:style> elements are converted to CssResources at compile time). So, you can have a CSS class named .warning in your WidgetA'a UiBinder template and a different .warning class in WidgetB'a UiBinder template. During compilation, they will get assigned different obfuscated names (since they are different classes). Now, let's move to your situation: you compile LibraryBundle and then you compile (independently) DepProjectBundle - it is possible (the shorter the obfuscation prefix, the more likely, and you should override the default long GWT prefix BTW) that in both projects you'll get the same named CSS classes (which of course will most likely have different purposes). So if you were to include blindly a class from LibraryBundle into DepProjectBundle, you might (at some point) introduce a name clash.
</tech (?) rant>

If you really want to avoid @external (which is a good idea, I'll admit :)), I'd suggest the following: include your LibraryBundle into your project as a svn:externals (you are using a SCM, right?) or a symlink or any other means available in your SCM or filesystem - basically, you'll be seamlessly able to share the same code of LibraryBundle amongst many projects (which I presume is the goal here), while having compile-time support from the GWT compiler.


Update in response to Steve's comments:

It seems I have misunderstood your project structure from your initial question - I was under the impression that you wanted to link to the compiled output of the LibraryBundle... But since you are working with the source (via Maven, nice :)), then my svn:externals idea is not needed (BTW, you can put any repository path in the svn:externals property, including your trunk branch).
Anyway, I was under the impression that one could easily combine two CssResources into one but alas... This is what I've tried so far, all failed, but maybe something from this list will spark some brilliant idea in someone ;) (cue a long list here...) Scratch that, in the process of summing up my failures I came up with the answer :)

And the answer is:

The @Import annotation (in combination with @ImportedWithPrefix for a more meaningful prefix). Your ProjectBundle would look like this:

public interface DepProjectBundle extends ClientBundle {
    public static final DepProjectBundle INSTANCE = GWT.create(DepProjectBundle.class);
    // Need this to reference the class names
    // But maybe we can use the one in LibraryBundle?
    // Have fun testing that :) For simplicty, I'll leave it here
    Library library();

    // The good stuff
    @Import({Library.class})
    Main main();
}

Library is a CssResource from your LibraryBundle (or maybe it can be the whole LibraryBundle? Haven't tried that). The important stuff is the @Import annotation (normal CSS @import url(some.css) doesn't work with ClientBundle - I've tried ;))
Now, you use this DepProjectBundle as such:

DepProjectBundle.INSTANCE.library().ensureInjected();
DepProjectBundle.INSTANCE.main().ensureInjected();
        
Label label = new Label("Test");
label.addStyleName(DepProjectBundle.INSTANCE.library().smallWindow());
VerticalPanel vPanel = new VerticalPanel();
vPanel.addStyleName(DepProjectBundle.INSTANCE.main().sectionA());
vPanel.add(label);
RootPanel.get().add(vPanel);

Note that we are using the DepProjectBundle.library() CssResource to reference the names from the library.css "namespace".
One important change is needed however in main.css - in order to avoid name clashes, the compiler imports the class names with a prefix - it uses either the classes' name or the one provided via the @ImportedWithPrefix annotation. So, your main.css will have to be changed to something like this (let's assume you used library as a prefix):

.sectionA .library-smallWindow {
  color: blue;
}

Unfortunately, there's no way around this (that I've found :)). But it might be beneficial in the long run - in case you forgot which names you used in the library.css and which in main.css (which could lead to some strange CSS clashes) - this way you clearly define (in main.css) that this class name belongs to the library.css (it gets obfuscated in the end, so no additional bytes are wasted).

Phew, hope this solution will be helpful to you (and others! :)) I'll leave my initial thoughts too, since someone else might not have been using (from the start :)) the source of the external ClientBundle, the svn:externals idea might be of use to someone not using tools like maven, etc.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜