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

Importing sheets with dependencies on other npm packages #466

Closed
marekpw opened this issue May 27, 2017 · 40 comments
Closed

Importing sheets with dependencies on other npm packages #466

marekpw opened this issue May 27, 2017 · 40 comments
Assignees

Comments

@marekpw
Copy link

marekpw commented May 27, 2017

I'm trying to import the @material/button library like this:

@import "~@material/button/mdc-button";

However the mdc-button tries to import from another library:

@import "@material/animation/variables";

Webpack/sass-loader understandably complains that the file is not found, because it's not prefixed with a tilde.

Is there any workaround/fix to this issue?

@Yizhachok
Copy link

Have the same issue

@borela
Copy link

borela commented Jun 1, 2017

@import "~@material/button/mdc-button/mdc-button.scss";
Or ask the owner of the package to add a main field in the package.json

@alexander-akait
Copy link
Member

@marekpw @Yizhachok @borela can your provide minimal reproducible test repo?

@marekpw
Copy link
Author

marekpw commented Jun 4, 2017

@evilebottnawi sure, here you go: https://github.com/marekpw/sass-loader-mdc/

As expected, prefixing the first import with tilde in @material/button/mdc-button.scss works, but it breaks on the next import.

@borela
Copy link

borela commented Jun 4, 2017

@marekpw got it, you need to add includePaths like so:

const { dirname, join, resolve } = require('path');
const webpack = require('webpack');

module.exports = {
    context: resolve('src'),
    entry: {
        app: './main.scss'
    },
    output: {
        filename: '[name].[hash].js',
        path: resolve('dist')
    },

    resolve: {
        extensions: ['.js', '.scss']
    },

    module: {
        rules: [
            {
                test: /\.scss$/,
                use: [{
                    loader: "style-loader" // creates style nodes from JS strings
                }, {
                    loader: "css-loader" // translates CSS into CommonJS
                }, {
                    loader: "sass-loader", // compiles Sass to CSS
                    options: {
                      includePaths: [
                        join(dirname(module.filename), 'node_modules')
                      ]
                    }
                }]
            }
        ],
    }
};

Here's a full package for compiling websites in you case you need hot reloading too.

@marekpw
Copy link
Author

marekpw commented Jun 4, 2017

Cool, that works. Thanks a lot.

@alexander-akait
Copy link
Member

alexander-akait commented Jun 6, 2017

@borela @marekpw bad solution, using includePaths option reduces performance.

@borela
Copy link

borela commented Jun 6, 2017

@evilebottnawi What's the other option?

@alexander-akait
Copy link
Member

@borela seems it is regression bug after #450 or #447

@borela
Copy link

borela commented Jun 6, 2017

@evilebottnawi I believe this bug was introduced before then, I had been using the includePath even for non scoped packages for a long time because the loader isn't using webpack's resolver, which is why I suggested custom extensions here.

It did seam counter intuitive to me to have to duplicate the paths from webpack's resolve.modules.

@alexander-akait
Copy link
Member

@borela I will try to solve this problem today or tomorrow, thanks!

@borela
Copy link

borela commented Jun 6, 2017

@evilebottnawi Thank you, I wish I could offer better help but I am still learning how webpack loaders work.

@marekpw
Copy link
Author

marekpw commented Jun 6, 2017

@borela as a workaround, it's still better than nothing for now :)

@alexander-akait alexander-akait self-assigned this Jun 6, 2017
@alexander-akait
Copy link
Member

alexander-akait commented Jun 6, 2017

Seems problems in node-sass (they don't support scoped import sass/node-sass#1596).
But it is possibly to solve throw imported, working on this.

@alexander-akait
Copy link
Member

/cc @michael-ciniawsky what do your think about problems? It's hard for me to imagine a solution for her, we can't add ~ in vendor sass styles 😞

@michael-ciniawsky
Copy link
Member

Besides the includePaths workaround there is no (clean) way to fix that atm, it would require node-sass to expose a hook to rewrite the @import paths before importing the contents

https://www.npmjs.com/package/sass-graph

https://www.npmjs.com/package/sass-module-importer
https://www.npmjs.com/package/node-sass-package-importer

Or writing our own :)

@michael-ciniawsky
Copy link
Member

@alexander-akait
Copy link
Member

@michael-ciniawsky yep, this is known, the question is whether we at the level sass-loader fix it or not

@michael-ciniawsky
Copy link
Member

It will require changes to sass-loader I would say, for the webpack glue (pre-resolving)

@michael-ciniawsky
Copy link
Member

What do you exactly mean by fix ? 😛

@alexander-akait
Copy link
Member

alexander-akait commented Jun 8, 2017

@michael-ciniawsky no new loader or something other stuff (options), just change logic in sass-loader which allow loading scoped importing in vendor sass/scss styles

@michael-ciniawsky
Copy link
Member

If possible we should do it :), I'm not too familiar with sass-loader internals and need to take a look myself first, if you have something in mind just propose it 😛

@ddobson
Copy link

ddobson commented Jul 11, 2017

I'm also experiencing this issue. I am trying to use primer-tooltips from the Primer CSS library. The index.scss file in that directory requires another file in a separate primer-support directory. When trying to build I get this error:

File to import not found or unreadable: primer-support/index.scss.
Parent style sheet: /Users/dale/Code/junk-drawer/node_modules/primer-tooltips/index.scss

If I change the @import statement in the file I'm trying to import in my project to @import "~primer-support/index.scss"; from @import "primer-support/index.scss";, it works.

Here is my webpack sass-loader config:

      {
        test: /\.scss$/,
        use: [
          {
            loader: 'style-loader', // creates style nodes from JS strings
          },
          {
            loader: 'css-loader', // translates CSS into CommonJS
          },
          {
            loader: 'sass-loader', // compiles Sass to CSS
          },
        ],
        include: [paths.appSrc, paths.appNodeModules],
      },

Additionally, I know I can import styles without other dependancies from node_modules because the import of Bulma CSS I'm using in my project is fine.

@alexander-akait
Copy link
Member

@ddobson workaround, but it is increase build time, no solution for this right now, but PR welcome

@mischkl
Copy link

mischkl commented Jul 20, 2017

Same problem here, I opened an issue with material components but looks like the issue is actually here.

material-components/material-components-web/issues/981

@alexander-akait
Copy link
Member

@mischkl old and known issue, solutions #479 (comment)

@mischkl
Copy link

mischkl commented Jul 20, 2017

@evilebottnawi @jhnns So basically anyone who wants to use the material components with webpack needs to build in this hack? Seems kind of like a poor solution.

What we really need IMHO is for sass-loader to process imports that occur within third-party modules differently than those that occur in the webpack project itself. For reference, everything that https://github.com/sass-eyeglass/eyeglass supports should ideally be able to be resolved by sass-loader, for the purpose of long-term interoperability of the third-party scss module ecosystem.

@alexander-akait
Copy link
Member

@mischkl it is not hack, it is correct solution. I agree we need search build-in solution for this, but it is not easy. Any ideas? PR welcome 👍

@mischkl
Copy link

mischkl commented Jul 20, 2017

@evilebottnawi well, my idea is stated right there: process @imports in third-party packages differently (could be as simple as pre-processing them to include a ~). Of course the implementation is another thing, but I imagine that it should be somehow feasible.

@alexander-akait
Copy link
Member

@mischkl it is breaking changes and can lead to a problem with performance and incompatibility, before think about this we should look how working less/stylus/etc loader with this problem (if they working with scoped packages). If I'm not mistaken node-sass don't work with scoped packages by default.

@mischkl
Copy link

mischkl commented Jul 20, 2017

If I'm not mistaken node-sass don't work with scoped packages by default.

@evilebottnawi you seem to be correct as judging by this issue: sass/node-sass#1596

As stated there the solution is to "use eyeglass". Which appears to be something like webpack, just limited to SCSS support... In any case it seems eyeglass does support importing scoped packages without a ~ prefix, which is the reason I suggested we use it as a reference.

The odd thing is that material-components themselves provide a demo that uses webpack. https://github.com/material-components/material-components-web/blob/master/webpack.config.js
Apparently they work around the issue by setting includePaths as follows:
includePaths: glob.sync('packages/*/node_modules').map((d) => path.join(__dirname, d))

@alexander-akait
Copy link
Member

@mischkl maybe this solution is right, it is really not easy to fix and i don't have ideas about this, but i am glad to hear any opinion and solution. Maybe we can fix this in node-sass and all packages which use this can handle scoped packages

@alexander-akait
Copy link
Member

@mischkl in theory any @package/style import which located in node_modules files should be resolve node-sass from node_modules directory, on the other hand node-sass just port sass on nodejs platform and don't care about this. I don't known who should this do 😞

@adityavohra7
Copy link

Say I have a project that deps two packages: package-A & package-B:

{
  "name": "nested-styles",
  "version": "1.0.0",
  "dependencies: {
    "package-A": "1.0.0",
    "package-B": "1.0.0"
  },
  "devDependencies": {
    "css-loader": "^0.28.5",
    "node-sass": "^4.5.3",
    "sass-loader": "^6.0.6",
    "style-loader": "^0.18.2",
    "webpack": "^3.5.5"
  }
}

And say [email protected] deps [email protected]. This will create the following install structure:

$ tree node_modules
...
├── package-A (@1.0.0)
│   ├── node_modules
│   │   └── package-B (@2.0.0)
│   │       └── sass
│   │           └── index.scss
│   └── sass
│       └── index.scss
├── package-B (@1.0.0)
│   └── sass
│       └── index.scss
...

nested-styles has an index.scss that imports styles from package-A:

// nested-styles/index.scss
@import "package-A/sass/index.scss";

body {
    background: $background;
}

where package-A/sass/index.scss is:

// node_modules/package-A/sass/index.scss
@import "package-B/sass/index.scss";

The following is my webpack.config.js:

module.exports = {
  entry: './index.js', // imports nested-styles/index.scss
  output: {
    filename: 'output.js',
  },
  module: {
    rules: [{
      test: /\.scss$/,
      use: ['style-loader', 'css-loader', {
        loader: 'sass-loader',
        options: {
          includePaths: ['node_modules'],
        },
      }],
    }],
  },
};

I'd like to get node-modules/package-A/sass/index.js to import styles from node_modules/package-A/node_modules/package-B/sass/index.scss (like how JS module resolution works). Is this something that's possible? With the current webpack.config.js, styles are imported from node_modules/package-B/sass/index.scss. Version conflicts, and therefore nested package structures, are pretty common IMO in node land, so I'd expect this to be solved problem, but I can't seem to figure out how 😢

@frederikprijck
Copy link

frederikprijck commented Aug 21, 2017

@adityavohra7 This sound like how node-sass works, any chance you can try to reproduce the exact behavior without using webpack, but by compiling ur sass using node-sass ?

You probably need something like:

node-sass --include-path scss scss/main.scss   public/css/main.css

More info on how to use node-sass: https://medium.com/@brianhan/watch-compile-your-sass-with-npm-9ba2b878415b

@adityavohra7
Copy link

@frederikprijck, I've created a repo to repro the behavior I'm seeing. I also tried compiling my sass directly with node-sass. With the following files:

// index.scss
@import "package-A/scss/index.scss";

body {
    background: $background;
}
// node_modules/package-A/scss/index.scss
@import "package-B/scss/index.scss";
// node_modules/package-B/scss/index.scss
$background: blue;
// node_modules/package-A/node_modules/package-B/scss/index.scss
$background: pink;

Calling node-sass yields:

~/nested-styles avohra$ ./node_modules/.bin/node-sass index.scss --include-path node_modules
body {
  background: blue; }

I'd like for that ^ to be "pink" (package-A deps a different version of package-B than nested-styles).

@frederikprijck
Copy link

frederikprijck commented Aug 21, 2017

@adityavohra7 So this looks like it's how node-sass is handling scss compilation, which isn't something sass-loader should deviate from.

Probably a good idea to open an issue on node-sass to get more information from them.

@robertmain
Copy link

I'm having an issue that I think is related where I try to `@import 'material-design-colors/material-colors' this package and I get the following error from webpack:

ERROR in ./node_modules/css-loader!./node_modules/sass-loader/lib/loader.js!./frontend/src/styles/main.scss
Module build failed:
@import 'material-design-colors/material-colors';
^
        File to import not found or unreadable: material-design-colors/material-colors.
Parent style sheet: <MY_PROJECT_DIR>/frontend/src/styles/utils/variables/_color_scheme.scss
        in <MY_PROJECT_DIR>\frontend\src\styles\utils\variables\_color_scheme.scss (line 1, column 1)
 @ ./frontend/src/styles/main.scss 4:14-128
 @ ./frontend/src/main.ts

Is this a related issue, or something else? I'm trying to @import the vendor style in my own sass sheets - rather than in vendor.ts

@alexander-akait
Copy link
Member

Sorry but we can not do anything here. So node-sass handle @import. Original issue sass/node-sass#1596

@UncleVic
Copy link

UncleVic commented May 7, 2018

@borela
It's very strange, but that solution doesn't work for me :(

But I found very simple solution for @Material library - you must install components with same version.
I removed my folder @Material and set up components step by step each time check version. My version is 0.35.0.
Now it compile fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests