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

6

13

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?

Kekkonen answered 10/11, 2019 at 21:26 Comment(0)
E
16

Here is the blog post about the new SASS module system. 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...

Eliathas answered 16/12, 2019 at 7:19 Comment(3)
That's what I figured. The only "fix" is to wait for Bootstrap to be rewritten with @use.Kekkonen
the link actually is invalidAnatomy
So should we go back to using @import?Withy
T
5

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.

Timothy answered 4/4, 2021 at 2:36 Comment(0)
N
3

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

Niccolo answered 13/2, 2020 at 16:55 Comment(0)
T
1

You can use meta.load-css for that:

@use 'sass:meta' as meta; // add this

// ...
// your code as above

$bootstrap-settings: (
  // variables override - see the docs for more info
);

@include meta.load-css('~bootstrap/scss/bootstrap', $with: $bootstrap-settings);
Taka answered 11/8, 2023 at 7:12 Comment(0)
E
0

This seems to work:

@use '~bootstrap/scss/bootstrap' as bs;

.container {
   @include bs.border-radius(1rem);
}
Ensure answered 6/6, 2023 at 16:24 Comment(0)
T
0

As of July 2024, Bootstrap is targeting switching to the Sass module system (@use/@forward, etc) in Bootstrap v6 (although who knows when that will be released), but that could change depending on when Sass deprecates @imports.

From Bootstrap's github:

For now, we'll try to stick to the original plan: in v6

  • dropping retro-compatibility support with Node Sass
  • switching to the new Sass major version + using module system

Depending on when the deprecation of imports is released in Sass, we'll maybe introduce modules sooner in an intermediate v5.X if necessary, but it's more of a backup plan for now IMO

The deprecation of @imports is still a little up in the air. At the beginning of May, nex, the lead dev of Sass, said:

@jathak reminded me that the plan is actually to deprecate @import before 2.0.0. We were waiting on the --silence-deprecation flag, but that's landed now, so we'll probably land the deprecation in the coming weeks.

But I think we're now past "the coming weeks" from then, so I guess it's been delayed for now.

Tychonn answered 24/7, 2024 at 4:42 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.