reactway / scss-bundle

Bundling SCSS files to one bundled file.
MIT License
56 stars 25 forks source link

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

Open arch-daemone opened 4 years ago

arch-daemone commented 4 years ago

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 commented 4 years ago

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:

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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?

DenysVuika commented 3 years ago

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

nickstaroba commented 3 years ago

@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 commented 2 years ago

Any updates on this? Is there a workaround?

sonikasharma1403 commented 2 years ago

Any update on this?

sumegha26 commented 2 years ago

https://github.com/reactway/scss-bundle/issues/90#issuecomment-1148634408

+1

pelord commented 2 years ago

@all Do you have a solution to fix this issue? I was refered to this issue from https://github.com/reactway/scss-bundle/issues/108

cgatian commented 2 years ago

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

DenysVuika commented 2 years ago

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 commented 1 year ago

This is till a problem it seems...

dkimmich-onventis commented 1 year ago

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 commented 1 year ago

Which new SCSS module system are you talking about?

dkimmich-onventis commented 1 year ago

@pelord see my updated comment

arch-daemone commented 1 year ago

@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 commented 1 year ago

@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.