Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Migrate to use the Sass module system #5220

Closed
jathak opened this issue Nov 1, 2019 · 22 comments
Closed

Migrate to use the Sass module system #5220

jathak opened this issue Nov 1, 2019 · 22 comments

Comments

@jathak
Copy link
Contributor

jathak commented Nov 1, 2019

As discussed offline with @abhiomkar and @aprigogin, we'd like to migrate the stylesheets in this repo to use the Sass module system.

I'm working on preparing a script that uses the Sass migrator to handle most of this migration, but I have a question about how to handle member prefixes.

Right now, most variables, mixins, and functions are manually namespaced with mdc-<component>-. Since the module system adds automatic namespacing, it makes sense to remove these manual prefixes (which the migrator can handle automatically).

However, there are two cases where this pattern doesn't quite hold:

Note that however we choose to handle namespacing during this migration, we'll add import-only files that forward the members with their original, manually-namespaced names. When downstream users migrate, the migrator will be able to detect this and automatically change these names when necessary.

@abhiomkar
Copy link
Collaborator

Thanks @jathak for the update!

  • We can leave color palette names as-is for import path by forwarding with material-color-* prefix.
  • This is interesting case, what options do we have? I wish @forward rule supports forwarding per mixin or variable name instead of file name.

Here is what I'm thinking:

Option 1

// rtl/_base.scss (Sass module)
@mixin rtl() {...}

// rtl/_mixins.scss (Sass module)
@mixin reflexive-box() {...}
@forward "base"

// rtl/_mixins.import.scss (Import path)
@forward "mixins" as mdc-rtl-*
@forward "base" as mdc-*

The first forward above might include mdc-rtl-rtl() mixin, but I think it should be fine. WDYT?

Option 2

Rename those mixins, but this requires changing all the places where these mixins were used. Not preferable.

@jathak
Copy link
Contributor Author

jathak commented Nov 4, 2019

For option 1, we wouldn't actually have to split it into a separate file, we could just do:

// rtl/_mixins.import.scss
@forward "mixins" as mdc-rtl-* hide mdc-rtl-rtl;
@forward "mixins" as mdc-* show mdc-rtl;

That should have the same effect as Option 1, but without requiring any new files. Would that work for you?

@abhiomkar
Copy link
Collaborator

I think that looks even better. Thanks! :)

@jathak
Copy link
Contributor Author

jathak commented Nov 5, 2019

One other non-standard namespace I found: for mdc-ripple, most members use a mdc-ripple prefix as expected, but the two functions in _functions.scss are prefixed with mdc-states instead. How should these be migrated?

@abhiomkar
Copy link
Collaborator

Can we do the same as above?

@jathak
Copy link
Contributor Author

jathak commented Nov 5, 2019

I think the three options here are:

  1. Remove the full prefixes from both mdc-ripple- and mdc-states-.
  2. Remove the full prefix from mdc-ripple- but only remove mdc- from mdc-states-.
  3. Remove only mdc- from both.

All three are possible, but it looks like there's also an mdc-states mixin, so for (1), that would still need to be handled like the others, and for both (1) and (2) we'd need to migrate a lot of this component manually since the migrator only supports one prefix per file. We'd also end up with fairly complex show/hide clauses to preserve the original prefixes in the import-only files. (3) would be the easiest for the migrator, but you would end up with longer names. Which would you prefer?

@abhiomkar
Copy link
Collaborator

Thanks for providing these options! I prefer an option which is backward compatible. I'm also open to renaming any of these mixins if you think the migration is getting super complicated, but I prefer it as last resort.

Here is what I'm proposing -

  • mdc-ripple
    • name in module system: ripple
    • import path: forwarded with mdc-*
  • mdc-ripple-radius-bounded
    • name in module system: radius-bounded
    • import path: forwarded with mdc-ripple-*
  • mdc-states
    • name in module system: states
    • import path: forwarded with mdc-*
  • mdc-states-hover-opacity
    • name in module system: states-hover-opacity
    • import path: forwarded with mdc-*

This makes the import path fully backward compatible. Please let me know your thoughts.

@jathak
Copy link
Contributor Author

jathak commented Nov 5, 2019

Yeah, that should work (it's mostly my option 2). I don't think there's any member named exactly mdc-ripple, so that shouldn't be an issue, and there's no real difference between mdc-states and mdc-states-something-longer from the migrator's perspective when it's only removing the mdc- prefix. I'll try to set up a script to migrate mdc-ripple this way and let you know if I run into issues.

@jathak
Copy link
Contributor Author

jathak commented Nov 18, 2019

An update on this: we realized that the module system as-is did not allow variables behind a @forward to be configured through an @import (which would mean migrating a library to the module system would prevent downstream users still on @import from configuring it). Since that blocks this migration, we've proposed a language change to support this and are working on the implementation now. See sass/sass#2772 for more details on this.

Another thing I realized is running the migrator in its current state on material-components-web could break downstream users that implicitly depended on files they didn't directly import (e.g. depending on a variable from mdc-theme while only directly importing mdc-button). Do you know how common this is / do we need to make sure we don't break this? The fix would be to have the migrator forward all dependencies that were previously available implicitly from an import-only file, which is feasible, but would take some time.

jathak added a commit to jathak/material-components-web that referenced this issue Dec 13, 2019
Add missing dependencies to three files that previously didn't depend on
all the stylesheets they reference (even indirectly). This caused issues
with the module system migrator (material-components#5220), so this fix is necessary for
that.
@jathak
Copy link
Contributor Author

jathak commented Dec 13, 2019

Update: I now have a shell script that automatically migrates most components (still working on chips, drawer, textfield, and select, which have subdirectories that make it harder to structure the migration).

This script works using a combination of Sass migrator (currently on a branch, but will be released once sass/migrator#131 is merged) and some sed scripts (primarily for ripple, due to the two prefixes). For users still using @import, it will preserve both prefixes and indirect dependencies, and those users should be able to use the migrator themselves to fix both of these when they switch to @use.

jathak added a commit to jathak/material-components-web that referenced this issue Dec 17, 2019
Add missing dependencies to five files that previously didn't depend on
all the stylesheets they reference (even indirectly). This caused issues
with the module system migrator (material-components#5220), so this fix is necessary for
that.
@jathak
Copy link
Contributor Author

jathak commented Dec 17, 2019

Updated the script with migrations for drawer and textfield (and in the process found two more files for #5337).

Now all that's missing is select, which is similar to textfield but has an issue where $mdc-select-icon-color is declared twice (not sure if intentional) that's crashing the migrator, and chips, which has a prefix/subdirectory structure that's more complicated than the others, so I'm not sure what to do there

@abhiomkar
Copy link
Collaborator

Thanks for the updates @jathak!

  • Regarding indirect imports, I've seen usages of mixins that did not necessarily have @import statements for them. It is not ideal but forwarding all its dependencies would help users for backward compatibility. Let me know if this is feasible or we can run a global test to see how many projects it is breaking.

  • Variable $mdc-select-icon-color defined in mdc-select/_variables.scss file is correct. We can remove the variable defined in mdc-select/icon/_variables.scss file. Thanks for spotting this!

jathak added a commit to jathak/material-components-web that referenced this issue Dec 19, 2019
Add missing dependencies to five files that previously didn't depend on
all the stylesheets they reference (even indirectly). This caused issues
with the module system migrator (material-components#5220), so this fix is necessary for
that.
allan-chen pushed a commit that referenced this issue Dec 19, 2019
Add missing dependencies to five files that previously didn't depend on
all the stylesheets they reference (even indirectly). This caused issues
with the module system migrator (#5220), so this fix is necessary for
that.
abhiomkar pushed a commit that referenced this issue Dec 20, 2019
Add missing dependencies to five files that previously didn't depend on
all the stylesheets they reference (even indirectly). This caused issues
with the module system migrator (#5220), so this fix is necessary for
that.
@jathak
Copy link
Contributor Author

jathak commented Jan 3, 2020

I now have the migrated code properly compiling when run directly through Dart Sass, but Webpack doesn't currently support import-only files, so migrating externally is blocked on webpack-contrib/sass-loader#788.

@jathak
Copy link
Contributor Author

jathak commented Jan 6, 2020

Dart Sass 1.24.2 fixes that issue. The big remaining issue on the GitHub side is how to handle lints. The following are what's failing now:

  • at-rule-no-unknown - Can be fixed by adding @forward and @use to the allowed list
  • scss-(dollar-variable|at-function|at-mixin)-pattern - Should be disabled, since a naming pattern is no longer necessary with the prefixes removed
  • max-line-length - The import-only files often after very long @forward lines when the same file has two prefixes, since it needs a bunch of hide clauses. The two options here are either to use some sort of formatter after the migration script, or just to ignore this lint for import-only files. Which do you prefer?
  • at-rule-empty-line-before - If the migrator ever adds a @forward rule and a @use rule for the same file, it puts a line break between the two sections. Is there a good way to make this lint ignore these cases?

@abhiomkar
Copy link
Collaborator

We would like to remove some of the custom lint rules from GitHub to keep it in sync with internal Sass lint rules.

I wouldn't mind removing above lints if these lints are not applicable internally. Let me know if you need any help removing above lint rules or would want me to remove these lints.

Thanks!

@jathak
Copy link
Contributor Author

jathak commented Jan 6, 2020

One more thing that came up when testing internally: button, checkbox, fab, switch, tab, and tab-scroller each have one or more mixins that are named using BEM syntax (e.g. mdc-button__icon_). Sass treats _ and - as equivalent in member names, so when the migrator removes a prefix like mdc-button-, the name becomes _icon_, making the resulting mixin enforced as private by Sass.

All of these mixins are already indicated as private with a trailing underscore, but there are some Google-internal files that do still reference them, and these references are broken by the migration.

My preferred solution to this would be to manually rename these mixins in a separate change prior to the module system migration and update the internal references accordingly. Does that work for you? If so, what new naming structure would you prefer for these mixins?

@abhiomkar
Copy link
Collaborator

SGTM.

We can rename these mixins from BEM-style to conventional mixin names. For example, mdc-button__icon_() => mdc-button-icon_(). Will this work?

@jathak
Copy link
Contributor Author

jathak commented Jan 6, 2020

Yeah, that works. Should I make the PR and CL or should you?

@jathak
Copy link
Contributor Author

jathak commented Jan 8, 2020

I'm working on figuring out migrations for the remaining 3 components. I think I have one working for mdc-select, but I have a questions about prefixes for the other two:

  • For mdc-textfield, most members use the mdc-text-field- prefix, but there are four variables that use mdc-textarea- instead. Three of these don't seem to be referenced anywhere and the fourth is only referenced once in mdc-web (and nowhere else internally as far as I can tell). Is it okay to just rename these to $mdc-text-field-textarea-... prior to running the script? (technically a breaking change, but no one seems to actually be using them)

  • For mdc-chips, most members use mdc-chip-, but there are two mixins with mdc-chip-set-. Is it okay to just remove mdc-chip- from all of them and leave those two mixins as set-core-styles and set-spacing? If not, how should these be handled?

@abhiomkar
Copy link
Collaborator

SGTM for textarea and chip-set. Thanks for clear comms.

@jathak
Copy link
Contributor Author

jathak commented Jan 9, 2020

One more thing for textfield that I didn't catch: there's a mixin called mdc-required-text-field-label-asterisk_. It's only use outside of mdc-web seems to be in mwc. Is this okay to rename?

@abhiomkar
Copy link
Collaborator

Yes, we can rename that mixin.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants