eduardoboucas / include-media

📐 Simple, elegant and maintainable media queries in Sass

Home Page:https://eduardoboucas.github.io/include-media/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

cannot import via `@use`

Hulkmaster opened this issue · comments

When i try to import lib via @use in .scss file i get an error

@use 'include-media';

SassError: Can't find stylesheet to import.
  ╷
1 │ @use 'include-media';
  │ ^^^^^^^^^^^^^^^^^^^^
  ╵

but works as @use 'include-media/dist/_include-media.scss';

Hi @Hulkmaster

@use 'include-media/dist/include-media should work also.

Sass has to understand where to to @import or @use modules from. This is usually defined in the includePaths config which is passed to the sass compiler. See https://github.com/sass/node-sass#includepaths

i'm not sure, but i think the matter is here

https://github.com/eduardoboucas/include-media/blob/master/package.json#L10

basically, as far as i remember, sass supports importing npm packages, but it needs proper entrypoint, so it should be changed to dist/_include-media.scss

Hmm. Not sure of the integration that is using that entry point. (CC @eduardoboucas ? ) I think your right in a way, but its probably due to the build tool you're using which would be handling that. Using sass cli, gulp-sass would handle this as far as I'm aware. Probably webpack would, but usually you still have to pass node_modules path to the sass-loader.

Looking at webpack docs. Looks like style or sass key is used in the package.json - include-media does have the sass key pointing to the right path.
It maybe that @use is not yet support via sure abbreviated paths. But again depends on your compiler a would imagine.

i actually have an example of library, which works like that

https://github.com/shannonmoeller/reset-css

we just use it as @use 'reset-css'

Using dart-sass cli, I had to add this to my script sass --load-path=node_modules/include-media/dist for @use "include-media" as im; to work (@use 'include-media/dist/_include-media.scss'; was not working for me)

node: v16.1.0
npm: 7.11.2
sass: 1.32.13

I came here for the same exact reason as @Hulkmaster and to provide the same input. If the path is set to the actual dist scss file then importing using just include-media should work. I'm not sure why the main entry in package.json is the index.js file which under the hood seems to do the same thing but in a more convoluted manner.

As @sethomas pointed out above, if you're going directly through the sass cli you need to include the dist dir in the --load-path for this to work, but if it was pathed properly in the main field i think you'd just be able to set the --load-path=node_modules without a direct path which would suffice for this and other packages which properly write the main field in package.json.

We happened upon this today completely by accident, because we use this package in a repo that gets published to a private npm instance and consumed by projects that then use webpack with the includePaths set to include node_modules, but in this case pre-publish we wanted to run some tests on the file to make sure it compiled and weren't able to do so until a full proper path was provided to the Sass CLI.

An easier and cleaner way to import this (and other things) seems to be using something like
sass-module-importer
. I can simply npm install include-media and then @import 'include-media'; without any problem. Trying to do @use "include-media" as im; causes a different set of problems for me. Sass clearly finds and loads it, but then this:

Fatal error: Error: "Invalid unit `layout-with-one-sidebar`."
    ╷
463 │     $_: im-log('Invalid unit `#{$unit}`.');
    │         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ╵
  ..\..\modules\ambientimpact\node_modules\include-media\dist\_include-media.scss 463:9    to-length()
  ..\..\modules\ambientimpact\node_modules\include-media\dist\_include-media.scss 434:15   to-number()
  ..\..\modules\ambientimpact\node_modules\include-media\dist\_include-media.scss 327:13   get-expression-value()
  ..\..\modules\ambientimpact\node_modules\include-media\dist\_include-media.scss 368:11   parse-expression()
  ..\..\modules\ambientimpact\node_modules\include-media\dist\_include-media.scss 558:22   media()
  ambientimpact_base\stylesheets\global\_layout.scss 217:5                                 on-sidebar-beside-content()
  ambientimpact_base\stylesheets\global\_layout.scss 298:5                                 @content
  ..\..\modules\ambientimpact\ambientimpact_core\stylesheets\helpers\_layout.scss 63:11    @content
  ..\..\modules\ambientimpact\ambientimpact_core\stylesheets\helpers\_selector.scss 143:5  root-conditions()
  ..\..\modules\ambientimpact\ambientimpact_core\stylesheets\helpers\_layout.scss 59:3     use-grid()
  ambientimpact_base\stylesheets\global\_layout.scss 296:3                                 layout-grid()
  ambientimpact_base\stylesheets\global\_layout.scss 380:5                                 @import
  ambientimpact_base\stylesheets\global\_global.scss 5:9                                   @import
  ambientimpact_base\stylesheets\_base.scss 9:9                                            @import
  ambientimpact_site\stylesheets\theme.scss 9:9                                            root stylesheet

Versions:

  • Dart Sass 1.43.4
  • Node 14.17.6
  • npm 6.14.15
  • sass-module-importer 1.4.0
  • Grunt 1.4.1
  • grunt-sass 3.1.0

Please ignore my previous issue; turns out this was because the breakpoints that I was adding after the fact weren't available to include-media. The solution was to wrap the call to @include media() { ... } in @include media-context($_breakpoints) { ... }. Since this would get annoying to maintain across many different partials, I wrote a simple mixin in my module that I now use:

@use 'include-media' as im;

///
/// Default set of breakpoints.
///
$_breakpoints: (
  'height-tiny':  30em,
  'height-small': 45em
);

///
/// Generate a media query based on a list of conditions.
///
/// This functions as a wrapper around include-media to automatically include
/// any custom named breakpoints that have been defined. Using the include-media
/// media() mixin directly with a custom named breakpoint would result in an
/// error if it was not also wrapped in the media-context() mixin, which is what
/// we do here.
///
/// @param {Arglist} $conditions
///   Media query conditions.
///
/// @require {mixin} im.media
/// @require {mixin} im.media-context
/// @require {variable} $_breakpoints
///
@mixin on($conditions...) {
  @include im.media-context($_breakpoints) {
    @include im.media($conditions...) {
      @content;
    }
  }
}

And you use it like so:

@use 'breakpoint';

@include breakpoint.on('<breakpoint name>') { ... }

Hmm, I am also still not able to get it working with @use. I am using gulp + dart-sass and my include-media file looks like this:

Scss/Vendor/_IncludeMedia.scss

@use "../Variable" as *;
@use "../../node_modules/include-media/dist/include-media";

and if I try to use it like this:

Scss/Component/Modal.scss

@use "../Mixin" as *;
@use "../Variable" as *;
@use "../Vendor/IncludeMedia" as *;

.modal {
    @include media("portrait", "<xs") {
      max-width: rem(320px);
    }
}

then I still get this error:

   ../app/vendor-private/distribution/Build/Scss/Component/Modal.scss
Error: Undefined mixin.
   ╷
39 │ ┌     @include media("portrait", "<xs") {
40 │ │       max-width: rem(320px);
41 │ └     }

I don't know if it matters, but my gulp config looks nearly like described here: https://www.npmjs.com/package/gulp-sass, and I also use v5.0.0 of gulp-sass with the following task configuration:

const cssPreprocessor = require('gulp-sass')(require('sass'))

const buildCssDev = () => {
    return glob(config.paths.scss, (err, files) => {
        if (err) {
            console.log(err)
        }

        const tasks = files.map((file) => {
            const fileData = file.split(/^\.\.\/app\/vendor-private\/(.+)\/Build\/Scss\/(.+).scss$/gm)
            const extensionName = fileData[1]
            const fileName = fileData[2].concat('.min.css')

            return gulp.src(file)
                .pipe(cssPreprocessor.sync().on('error', cssPreprocessor.logError))
                .pipe(cssAutoPrefixer())
                .pipe(cssCleaner(config.plugin.cssCleaner))
                .pipe(rename(fileName))
                .pipe(gulp.dest('../app/vendor-private/' + extensionName + '/Resources/Public/Css/'))
        })

        eventStream.merge(tasks)
    })
}

So I think it's not really special, but as I said @use is currently not working for me. :(

Maybe someone has any suggestions? :)

@Mainbird in your Scss/Vendor/_IncludeMedia.scss you need to import all the files and then your can use @use "../Vendor/IncludeMedia" as *; without needing to @use "../Variable" as *;` too.

You only need to import once. and then use whenever you want to use those mixins and vars.

@jackmcpickle thanks for your example :), but in your example, you also take usage of @import which as I understand is outdated if you are working with dart sass (see first heads up section here: https://sass-lang.com/documentation/at-rules/import):

src/_includes.scss

@import 'vars';
@import 'include-media/dist/include-media';

and if I modify this to

src/_includes.scss

@use 'vars' as *;
@use 'include-media/dist/include-media';

then I will get the same error as described in my example above. :(

If I modify your example to a mix of both:

src/_includes.scss

@use 'vars' as *;
@import 'include-media/dist/include-media';

then I have to modify app.scss, too:

src/app.scss

@use 'includes' as *;
@use 'vars' as *;

@include media('>sm') {
    body {
        background-color: $bg-colour;
    }
}

This will work, but also make usage of one @import rule which I want to remove as well :)

@jackmcpickle if I modify your example to:

src/app.scss

@use 'vars' as *;
@use 'include-media/dist/include-media' as * with (
    $breakpoints: $breakpoints
);

@include media('>sm') {
    body {
        background-color: $bg-colour;
    }
}

then it will work without any @import rule, too. :)
If I want to do this with an additional file, then I have to do it like this:

src/_include.scss

@use 'vars' as *;
@forward 'include-media/dist/include-media' with (
    $breakpoints: $breakpoints
);
src/app.scss

@use 'includes' as *;
@use 'vars' as *;

@include media('>sm') {
    body {
        background-color: $bg-colour;
    }
}

this will work for me as well without any @import rule. :)