Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't @use or @forward a file #90

Open
arch-daemone opened this issue Apr 23, 2020 · 18 comments
Open

Can't @use or @forward a file #90

arch-daemone opened this issue Apr 23, 2020 · 18 comments

Comments

@arch-daemone
Copy link

arch-daemone commented Apr 23, 2020

Describe the bug
Despite using the latest version of sass, which implements the new module system, scss-bundle won't let me use @use or @forward to import a file. Having just refactored a massive monorepo (136 files touched) to use the new system, this was not a nice thing to see in our Jenkins console.

To Reproduce
Steps to reproduce the behavior:

  1. Create a new directory, with two files, index.scss and _child.scss
  2. In index.scss write the line @use 'child';
  3. In _child.scss write some basic CSS, like body { height: 100%; }
  4. Run scss-bundle with index.scss as the entryFile
  5. Terminal prints an error that it "Can't find stylesheet to import", pointing to the line with the @use.
  6. Observe that if you change to using @import, everything works as expected.

Expected behavior
I would expect files imported with @use or @forward to be found and bundled correctly.

Package version: v3.1.1
Node version: v12.14.1
OS: Windows (but also Bash on the Jenkins box)

@arch-daemone
Copy link
Author

arch-daemone commented Apr 25, 2020

Ah. I started looking into this myself this morning, thinking I could maybe submit a PR, and discovered that it would actually be quite a lot of work! Since you can't just pass off to Sass itself to do the hard work of bundling, scss-bundle would have to fully implement all the new behaviour of the module system. Off the top of my head:

  • "used" modules' variables/functions/mixins need to be namespaced, both in the declaration and in the usage:
    • a.$variable --> $-a--variable or something (made private because used variables are not re-exposed);
    • Significantly, this needs to account for both @use 'foo' and @use 'foo' as bar syntax when it comes to finding usages, and ideally should be done in such a way that the used file is only included in the bundle once, and its variables referenced repeatedly wherever the file is re-used;
    • In fact, the namespaces we assign should be something generated and highly likely guaranteed to be unique, so they can effectively be reused globally within the bundle file;
  • forwarded variables need to be made a part of the same namespace as those of the used file that forwards them;
    • Also, uses of @forward 'foo' as foo-* syntax need to add the inner namespace to the names of variables, as well as the outer namespace of the module doing the forwarding;
  • Private variables (marked by identifiers that start with - or _) need to essentially be erased from the bundle: their values calculated and uses of them replaced with the calculated values - there's no other way to ensure that they aren't exposed;
  • Uses of @use 'foo' with () need to correctly assign to the named variables the values that are being passed in;
    • But only the first time the module is used. All subsequent imports should use the values provided the first time, and scss-bundle should throw an error if more than one module tries to configure the same module with with;
  • Of course, the major one: with all of these approximations of the module behaviour, what's actually exposed to consumers of the bundle still needs to be what would be expected if the whole thing were still separate modules,

I'm sure there are other things to add (especially in the area of errors to throw) but already that's got it looking pretty complex. I'd still like to take a pop at it, but if one of the more regular contributors can see a solution and beats me to it, I'll be happy with that too!

@DovydasNavickas
Copy link
Member

DovydasNavickas commented Apr 25, 2020

@DaemonExMachina, glad you took a look into this. We departed from using scss-bundle and even scss itself into using CSS-in-JS provided by Emotion, so this module system is new to us.

Looking at your last post (it is pretty exhaustive, thanks for that!) it seems that the module system is quite similar to JavaScript / TypeScript ones. Just not sure what does @use 'foo' with () would do yet 😄

Your observation about scss-bundle needing to implement a lot of things is correct too. Right now, scss-bundle only keeps a registry of files, dedupes them, and prints everything into a respective. Supporting module system though needs reading the SCSS AST and most probably manipulating it, which isn't foreign to us as we've worked with various tools using AST. But at the same time, as we're not using SASS for quite some time, it would be a rather large investment into researching and implementing everything.

If you want to tackle this, please do. We can support you, but having neither financial benefit nor usage in our organization, it's unlikely we are going to implement this very soon.

@arch-daemone
Copy link
Author

Ah yeah, if you haven't been reading up on the new modules some of what I wrote would be absolute gobbledygook!

I totally get why this wouldn't be a priority in that case. To be perfectly honest, we're working towards not needing scss-bundle too, but I'm not sure how long that's going to take. There are a few steps to get there, and we may not even go all the way there. Basically, if we can get away with using CSS custom properties (variables) for theming, then we don't need to build a SCSS bundle to export for clients to manipulate to build their own themes. They can just write some overrides for the (many many) CSS variables and attach them to :root.

I'm interested in the challenge of making this change, though. Playing with parsers, reading ASTs... yeah, that's something I've always wanted to explore but never had reason to. Every build tool and linting rule I've needed so far has already been built by someone.

Just for fun, then: the with syntax allows you to configure a module the first time you load it. You declare some variables with the !default flag in the consumed module, and the first module that loads it then passes it values for those variables.

// _child.scss
$var1: blue !default;
$var2: null !default;

body {
  color: $var1;
}

// index.scss
@use 'child' with (
  $var1: red,
  $var2: green
);

It's a concept that already existed: a browse through the Bootstrap stylesheets, for instance, would show lots of those !default values. But you would just declare the overrides globally before importing, and that would be that. Here it's much more explicit that these are being passed in, and there's no fear of name collisions or other accidental interference.

@marksmccann
Copy link

Do we anticipate an progress being made on this feature enhancement? If so, is there anything I can do to help? If not, do you know of any good workarounds? In my head, this enhancement would be perfect for my use case, but maybe there is an alternative I am not considering?

PowerKiKi added a commit to Ecodev/natural that referenced this issue May 25, 2021
Because it is not compatible with the new `@use` from SASS:

reactway/scss-bundle#90

So instead we ship raw SCSS files to be consumed by the app.
@DenysVuika
Copy link

This is a blocker for us as well, any plans to resolve this issue?

@nickstaroba
Copy link

@DenysVuika One workaround I found was to create a "set up" file that has only your @use statements and then bundle that file first. I'm using gulp:

src("./src/_setup.scss").pipe(src("./src/_other-file.scss")).pipe(concat("index.scss")).pipe(dest("./dist"))

It's not a the best solution since you can't have the @use statement at the top of the other individual scss files, but it's working well enough.

@sergiubologa
Copy link

Any updates on this? Is there a workaround?

@sonikasharma1403
Copy link

Any update on this?

@sumegha26
Copy link

sumegha26 commented Jun 17, 2022

#90 (comment)

+1

@pelord
Copy link

pelord commented Jul 12, 2022

@ALL Do you have a solution to fix this issue?
I was refered to this issue from #108

@cgatian
Copy link
Contributor

cgatian commented Jul 12, 2022

I've contributed to this repository and can say that without a major refactor/rewrite this feature will never happen.

@DenysVuika
Copy link

we had to completely get rid of this tool and using Angular CLI and synthetic app project to compile the themes so far

@scott-rothman
Copy link

This is till a problem it seems...

@dkimmich-onventis
Copy link

dkimmich-onventis commented May 11, 2023

I feel like with the new SCSS module system (@use & @forward), this package is obsolete for most users. You can achieve the same without the need of bundling everything into one single file. In your index.scss, just @forward all the files you want to expose, instead of importing them.

Before:

@import 'child1';
@import 'child2';

After:

@forward 'child1';
@forward 'child2';

All the variables and mixins exposed from the children will be available from the root entrypoint.

@pelord
Copy link

pelord commented May 11, 2023

Which new SCSS module system are you talking about?

@dkimmich-onventis
Copy link

@pelord see my updated comment

@arch-daemone
Copy link
Author

arch-daemone commented May 11, 2023

@dkimmich-onventis This package is for a very particular use-case. The desired end result is a single .scss file that bundles your separate files, but still as SCSS. Using a Sass compiler converts it into CSS, which is not desired. If that sounds odd, then it's because you don't have that use-case. Which is fine! Most teams don't.

Take the reason my team was using scss-bundle, for instance (spoiler alert: we don't use it anymore). We were trying to generate an Angular Material theme bundle that could be patched with custom palettes by our clients at deploy-time. They just create a theme.scss file that contains @use 'app/theme';, and then @include our configurating mixin with their palettes. Our init-container then automatically compiles that into an actual CSS file during deployment.

The part that matters here is that that imported app/_theme.scss file was a single bundled file containing our own theme-specific SCSS code, all of the Angular Material SCSS, and some more SCSS from our company's central Angular library. The only export from that huge bundled file was (supposed to be) our own single mixin, but it referenced everything else internally and passed on the palettes to other mixins. Bundling up this bundle at the same time as our app is built was the reason we used scss-bundle. The steps were:

  1. Build-time
    • Build the app (including a default theme.css using our default palettes);
    • Build the init-container (including an uncompiled (but bundled) _theme.scss file for the client to import);
  2. Deploy-time
    • If the client has a theme.scss file, build a new theme.css using it and the _theme.scss bundle from the init-container;
    • If not, just use our default theme.css.

Because I didn't have anywhere near the time to make this change to scss-bundle myself, and no one else seemed likely to do it, I ended up just moving us away from using it. Now, our init-container is filled up with all of node_modules/@angular/**/*.scss (and some other similar globs from other npm scopes), and the app/_theme.scss file our clients import. And it works just as well. It's just lots of files, instead of one file.

@LinboLen
Copy link

@use @forward can't implement by bundle, it based on file and folder witch like a namespace. if bundle it together the namespace info will gone. so may introduce new scss grammar like namespace feature then the bundle may works.
if want to override @use @forward scss theme. may use path rewrite. like _theme.scss file can put in project root or node_modules folder, the webpack may try to search project root first then can search node_modules path.

passiondev2024 added a commit to passiondev2024/natural that referenced this issue Mar 21, 2024
Because it is not compatible with the new `@use` from SASS:

reactway/scss-bundle#90

So instead we ship raw SCSS files to be consumed by the app.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests