rules_closure icon indicating copy to clipboard operation
rules_closure copied to clipboard

CSS rewriting not working in JS templates

Open sgammon opened this issue 4 years ago • 4 comments

tl;dr CSS rewriting does not seem to be working, at least in terms of JS' invocation of getCssName.

Given the following setup (WORKSPACE and related wiring omitted):

sample.soy:

{namespace sample.tpl}

{template .sample}
  <div class="{css('hello')}">
    <b>hi</b>
  </div>
{/template}

sample.css:

.hello {
    background: blue;
}

sample.js:

goog.provide('sample');
const soy = goog.require('goog.soy');
const tpl = goog.require('sample.tpl');

const docFrag = document.createDocumentFragment();
const el = soy.renderAsElement(
  docFrag,
  tpl.sample,
  {},
  {});

document.body.appendChild(docFrag);

BUILD.bazel:

closure_css_library(
  name = "sample-css",
  srcs = ["sample.css"],
)

closure_js_template_library(
  name = "sample-tpl",
  srcs = ["sample.soy"],
  deps = [":sample-css"],
)

closure_css_binary(
  name = "sample-styles",
  deps = [":sample-css"],
)

closure_js_library(
  name = "sample-js",
  srcs = ["sample.js"],
  deps = [
    ":sample-tpl",
    "@io_bazel_rules_closure//closure/library/soy:soy",
  ]
)

closure_js_binary(
    name = "sample",
    debug = False,
    entry_points = ["sample"],
    deps = [":sample-js"],
    css = ":sample-styles",
)

When I build and run the resulting JS, the template renders, but it renders with the original CSS names, whereas, the CSS has been rewritten. This breaks styles, of course.

Digging into the intermediates: bazel-out/darwin-fastbuild/bin/.../sample.js-0.params:

external/com_google_javascript_incremental_dom/.../lots.js
external/com_google_javascript_incremental_dom/.../of.js
external/com_google_javascript_incremental_dom/.../sources.js
...
...
...
bazel-out/darwin-fastbuild/bin/.../sample.css.js
--define=now=true
--define=some=true
--define=defines=true

The last entry in the set of input files, is a file that ends in css.js. Examining that file, it looks like we're on the money:

goog.setCssNameMapping({
  "material": "a",
  "icons": "b",
  "hidden": "c",
  "mdl": "d",
  "button": "e",
  "no": "f",
  "select": "g",
  "numeric": "h",
// ...

In the generated template file, it seems to know what's going on (as in, it's using goog.getCssName):

      incrementalDom.attr('action', '#');
      incrementalDom.attr('class', goog.getCssName('page-welcome--form-module') + ' ' + goog.getCssName('page-welcome--form-account'));

But, in the final output JS, it uses the original classes: Screen Shot 2019-07-08 at 12 37 22 AM

Anybody have any ideas? Or, at least, is anyone seeing the same behavior?

sgammon avatar Jul 08 '19 07:07 sgammon

Did some digging and it definitely seems like rules_closure is doing what it should. Cross-filed with GCC at google/closure-compiler#3427.

sgammon avatar Jul 10 '19 05:07 sgammon

after some discussion on google/closure-compiler#3427, and a sample repo at sgammon/css-rewrite-bug, it has been determined it isn't the compiler, which of course was likely.

it now seems like it might be an issue inside J2CL, because i can't get rules_closure to build the sample at all without wrapping it in j2cl_application. more to come, if anybody is hitting this same issue

btw if you are getting issues with symbols-already-defined for goog.soy or soy, try building through j2cl_application. i have no idea why it works but it does.

sgammon avatar Jul 11 '19 19:07 sgammon

The issue is that you set dependency_mode = "STRICT", which will eliminate all files that are not in the transitive closure of entry_points (i.e. not in entry_points and never goog.required). As a workaround, you can

  • set dependency_mode = "PRUNE_LEGACY" which will include all files without goog.{module,provide} as entry points (https://github.com/google/closure-compiler/blob/445fdf3f31d848d955d71d10f4794b45c0f4d1a6/src/com/google/javascript/jscomp/CommandLineRunner.java#L805), or
  • add src/sample-styles.css.js as entry point

We should probably automatically add the css rewrining map as an entry point.

Yannic avatar Sep 07 '19 12:09 Yannic

Also, dependency_mode = "STRICT" is deprecated. You should switch to dependency_mode = "PRUNE" which has the same effect:

https://github.com/google/closure-compiler/blob/445fdf3f31d848d955d71d10f4794b45c0f4d1a6/src/com/google/javascript/jscomp/CommandLineRunner.java#L145

Yannic avatar Sep 07 '19 12:09 Yannic