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 CssResource
s 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 CssResource
s 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.
精彩评论