Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Importing Bootstrap into my SCSS via @use instead of @import causes problems

My project extends Bootstrap's responsive breakpoints. Here is the entrypoint SCSS file that was working for me:

@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";

$magnetar-grid-breakpoints : (
    1440: 1440px,
    1600: 1600px,
    1920: 1920px,
    2560: 2560px
);
$grid-breakpoints : map-merge($grid-breakpoints, $magnetar-grid-breakpoints);

$magnetar-container-max-widths : ();

@each $key, $val in $magnetar-grid-breakpoints {
    $magnetar-container-max-widths : map-merge($magnetar-container-max-widths, ($key : 0.95 * $val));
}

$container-max-widths : map-merge($container-max-widths, $magnetar-container-max-widths);

@import "~bootstrap/scss/bootstrap";

I'm just getting started on this project, and already I can tell that having to prefix all my variables (and mixins and functions) with "magnetar-" in order not to have conflicts with Bootstrap will get old fast. Therefore I thought I'd give the new Sass modules system a try and use @use instead of @import. Here is the rewritten SCSS:

@use "~bootstrap/scss/functions" as bootstrap_func;
@use "~bootstrap/scss/variables" as bootstrap_var;
@use "sass:map";

$grid-breakpoints : (
    1440: 1440px,
    1600: 1600px,
    1920: 1920px,
    2560: 2560px
);
bootstrap_var.$grid-breakpoints : map.merge(bootstrap_var.$grid-breakpoints, $grid-breakpoints);

$container-max-widths : ();

@each $key, $val in $grid-breakpoints {
    $container-max-widths : map.merge($container-max-widths, ($key : 0.95 * $val));
}

bootstrap_var.$container-max-widths : map.merge(bootstrap_var.$container-max-widths, $container-max-widths);

@use "~bootstrap/scss/bootstrap";

But the above compiles with this error:

SassError: @use rules must be written before any other rules.

It's referring to the last line. So I thought I'd try changing that line back to @import. That resulted in this error:

SassError: $color: theme-color("primary") is not a color.
    ╷
174 │ $link-hover-color:                        darken($link-color, 15%) !default;
    │                                           ^^^^^^^^^^^^^^^^^^^^^^^^
    ╵
  node_modules\bootstrap\scss\_variables.scss 174:43  @use

I'm lost as to what this means. Any ideas?

like image 910
William Beaumont Avatar asked Nov 10 '19 21:11

William Beaumont


Video Answer


3 Answers

Here is the blog post about the new SASS module system: http://sass.logdown.com/posts/7858341-the-module-system-is-launched

This mentions the following:

In addition to namespacing, there are a few important differences between @use and @import:

  • @use only executes a stylesheet and includes its CSS once, no matter how many times that stylesheet is used.
  • @use only makes names available in the current stylesheet, as opposed to globally.
  • Members whose names begin with - or _ are private to the current stylesheet with @use.
  • If a stylesheet includes @extend, that extension is only applied to stylesheets it imports, not stylesheets that import it.

The bold statement is why it doesn't work with the @use directive. All imported functions are not available globally, meaning the file ~bootstrap/scss/variables does not know about the functions declared in ~bootstrap/scss/functions.

I honestly have no idea how to fix this though...

like image 56
Didii Avatar answered Feb 22 '23 21:02

Didii


You are getting an error because you are using other statements before your final @use statement - namely the statements to override the values for $grid-breakpoints and $container-max-widths.

With the @use rule you need to use the "with" keyword to override those imported values, rather than defining your overrides first and then using @use.

Since you are importing the entire Bootstrap scss anyways there is no need to separately import the _vars and _functions. Just use the statement:

@use "yourpath/bootstrap/scss/bootstrap" with ( <your overrides here>)

I am not sure how you would use an iterator inside that "with"-statement.

A working solution for what you are doing would look like this (sorry, I don't have an iterating solution, just literal assignments):

    @use "~bootstrap/scss/bootstrap" with (
  $grid-breakpoints:(
  xs: 0,
  sm: 576px,
  md: 768px,
  lg: 992px,
  xl: 1200px,
  1440: 1440px,
  1600: 1600px,
  1920: 1920px,
  2560: 2560px
  ),
  $container-max-widths :(
    sm: 540px * 0.95,
    md: 720px * 0.95 ,
    lg: 960px * 0.95,
    xl: 1140px * 0.95,
    1440: 1280px,
    1600: 1480px,
    1920: 1800px,
    2560: 2300px
  )
);

Tipp: Without the "as" keyword the namespace will automatically be the last bit bit of your path i.e."bootstrap" (and there is no scope problem for _variables to know _functions and vice versa as was suggested in another comment).

Please find documentation for all this on the sass-lang.com website: https://sass-lang.com/documentation/at-rules/use

like image 21
Sketchbookshark Avatar answered Feb 22 '23 21:02

Sketchbookshark


Just to elaborate on the accepted answer, Bootstrap team argues that they can't migrate to @use because most compilers are yet to support it (even though Sass team doesn't recommend @import any more).

In short: we can't switch to the new Sass module system yet because the majority of build systems doesn't support @use or @foward yet.

One day we will probably switch though (probably in v6).

Source.

like image 24
alotropico Avatar answered Feb 22 '23 21:02

alotropico