Meteor: [1.3] Style files imports from node_modules

Created on 19 Jan 2016  Â·  117Comments  Â·  Source: meteor/meteor

How to import .scss files located in the installed npm package (in node_modules). For example I do:

npm install foundation-sites --save

And now I want to import .scss files from node_modules/foundation-sites
I mean something like (in main.scss in the app):

@import 'foundation-sites/scss/foundation.scss';

I've tried many combinations, like {}/node_modules/foundation-sites... , {}/foundation-sites..., /node_modules/foundation-sites..., etc.

Nothing works with fourseven:scss.

Do we have a solution for this in Meteor 1.3? I gues that node_modules is ignored so .scss compiler doesn't see the files. I think this is the use case when compiler should see node_modules folder.

Most helpful comment

just wanted to reiterate that this is definitely coming in 1.3.1

All 117 comments

This is definitely an interesting feature to consider. Right now this won't work because only .js and .json files can be imported from node_modules directories. Additionally, we don't run compiler plugins on files in node_modules directories (related: #5892). Finally, .scss files don't use the JS module system currently, though perhaps fourseven:scss could be updated to generate CommonJS instead of CSS resources.

I'm going to leave this issue open but remove it from the Meteor 1.3 milestone for now, because I'm doubtful we will have a solution for this by the time we release 1.3 (but perhaps as soon as ~1.3.1).

Ok, thanks.
@sebakerckhof and @fourseven may also be interested in it.

Okay, some context: Currently Meteor feeds entry-point (=non-imports) .scss files into our compile plugin (fourseven:scss). Most of the code of our plugin is about handling imports (with respect to cross-package imports etc.). Some limitations of node-sass/libsass make this a bit harder than for stylus/less.

If I understand correctly (warning: I haven't looked into meteor 1.3) 2 things should change:
1) We should be able to generate commonjs files. I know CSS and I know CommonJS, but I have absolutely no idea what these have in common and how I should generate commonjs files from scss.

2) Meteor should feed us with scss files from node_modules directory. But how does this play together with the current cross-package import syntax (= {packagename}/file.scss)? In this case, what does {packagename} refer to?

I don't know exactly how it works internally, but I think we need to treat node_modules (it is in app root dir) as a normal directory when importing in .scss file. I don't know if we need imports in CommonJS-sense. I mean scss imports only (at least for now). And {package:name}/myfiles.scss could still work the same way.

So if now I can do @import 'my-other.scss' (from the same folder) then I should also do @import /node_modules/package-name/other.scss or maybe @import {}/node_modules/package-name/other.scss or even better just @import 'the-name-of-npm-module-installed-in-node_modules/other.scss' and it seems like scss builder doesn't see node_modules

This is how I understand it, but I don't know exactly how Meteor treats node_modules dir in v1.3 and how fourseven:scss works.

I've been able to come to somewhat of a solution using fourseven/meteor-scss. In the root of your app you should have a file scss.json where you include the path to your package(s):

{
  "includePaths": [
    "node_modules"
  ]
}

Then you can import them in your scss file by @import "foundation-sites/scss/foundation.scss";

@thatgibbyguy cool! It should be enought for now, but I think that imports from node_modules should be allowed by default in Meteor ;) anyway, thanks for that info.

One of the reasons I was hesitant to include anything other than .js and .json files in node_modules directories was that node_modules directory trees can be really large, and I was worried about build times getting much longer.

It occurs to me that there is a middle ground: we could allow any files in direct node_modules/* dependencies to be imported, but ignore files in nested (indirect) dependencies (node_modules/*/node_modules/*).

If we do that, then if you want to import a non-JS file from a package in node_modules, you just have to make sure it is installed as a direct dependency, which seems pretty reasonable to me.

@benjamn Yeah, an alternative would be like this:

{
  "includePaths": [
    "node_modules/foundation-sites/scss"
  ]
}

@import "foundation.scss";

@benjamn yeah, it would be great. Also I wonder if we want to import other files than js, json, css, less, styl, scss, sass.

Also I hope that something like importing the file which imports another file from the same level 'node_modules' will still work. But this is probably fourseven:scss (and other build plugins) competence.

In the future it'll be cool to have something like Webpack's css and images loaders, also CSS Modules. To build better separation of components. But this is for the future I gues).

@thatgibbyguy is your scss.json file support to get it working with the current beta-5 build of Meteor? It still acts like it can't find the file to import when I try it.

Also, this is unclear @benjamn is this going to be worked on before release, or no? Because Meteor 1.3 completely breaks the zurb:foundation-sites package and doesn't seem to work at all with the NPM version of foundation for @import. Seems like a deal breaker for a lot of people.

@queso there is one caveat with scss.json (and I cannot find documentation on this for the life of me) where you need to rebuild meteor before you can utilize what you've set in scss.json.

So what this means is comment out your imports in your main sass file and restart meteor. After that your imports should work fine.

@queso zurb:foundation-sitesis broken in 1.3 because of motion-ui usage. There is a discussion here: https://github.com/zurb/foundation-sites/issues/7896 If we have proper imports from npm_modules I think we don't need Meteor package (zurb:foundation-sites). If there will be no possibility to import .scss files from node_modules then we need to remove motion-ui from zurb:foundation-sites and create a standard separated meteor package for example zurb:motion-ui.

It was done like that because in the past motion-ui was required by some of foundation's js plugins and there wasn't a simple way to include it. Now it isn't required. So I gues that Foundation team will wait for Meteor 1.3 official release. Because for now there isn't a clear path what should be done. Personally I prefer abandon zurb:foundation-sites and make usage of npm package ;) But without proper imports in .scss files from node_modules it won't work that way. So, yeah, this is a deal breaker in this case and many similar.

@juliancwirko yeah, I saw that, and I agree that the proper way forward is to use the npm version because it will reduce load on outside projects having to care how Meteor compiles and/or packages files.

@thatgibbyguy sorry to be dense, but I added the scss.json file to the root of my 1.3 app and restarted everything. Still no luck:

While processing files with fourseven:scss (for target web.browser):
   /client/stylesheets/main.scss: Scss compiler error: File to import: {}/client/stylesheets/foundation-sites/scss/foundation.scss not found in file: /Users/josh/Code/Clients/clientA/{}/client/stylesheets/main.scss

My main.scss file is just this:

@import 'foundation-sites/scss/foundation.scss';

I think @thatgibbyguy uses the old meter-scss (v1.2) plugin. Because later versions don't use scss.json anymore. That old version kind of bypasses the meteor compiler system and just reads the files from disk itself. It also doesn't support cross-package references.

@sebakerckhof is right. I'm using fourseven:scss@=3.2.0

@thatgibbyguy Yeah, 3.2 is what I meant to say. The changes I describe are from 3.3 up.

IMO we really need a solution for this. I'm trying to use materialize-css with material-ui (NPM) and not having any luck. I either have to include materialize-css via HTML, which causes collisions with material-ui, or add the meteor package which has the same problem. I just want to be able to use @import to include what I need. And I can't get help from anywhere else, because most people still don't know about Meteor, and make suggestions like using webpack or some other solution that we Meteor (1.3) folks don't need to worry about.

Meteor 1.3 is almost useless without node_modules assets import.
IMHO this must be solved on 1.3 and I don´t undestand why is scheduled after on 1.3.1 or beyond.

Right now I'm trying a 1.3 project integration with https://github.com/thereactivestack/meteor-webpack only for import .scss files from node_modules and only have errors and meteor fatigue

Please MDG make a last effort on this ...

I agree with @ffxsam, @bySabi and the rest of the coders in here. I also have issues with this, and would love to see it in one of the near 1.3 beta releases.

We believe in you MDG <3

IMHO this must be solved on 1.3 and I don´t undestand why is scheduled after on 1.3.1 or beyond.

I would assume because this would be new scope, and 1.3 is close to ready. Delaying 1.3 for this would be a mistake IMO, even though I got bit by this as well.

What I've done to solve this for now is I've created a folder in the root of my project and anytime I need to import something I make a symbolic link to the file I need in node_modules. Works for my use cases for now!

@ffxsam this is not about CSS Modules, we just can't import other .scss or .less files from node_modules in our main .scss or .less files in the app. W can't just install an NPM package and import some of its .scss files from node_modules like:

in project/app.scss:

@import '{}/node_modules/awesome-scss-package/scss/buttons.scss';
@import '{}/node_modules/awesome-scss-package/scss/grid.scss';

Oops - I didn't read carefully ;) deleting my post.

[email protected]
On Mar 11, 2016 9:33 AM, "Julian Ćwirko" [email protected] wrote:

@ffxsam https://github.com/ffxsam this is not about CSS Modules, we
just can't import other .scss or .less files from node_modules in our main
.scss or .less files in the app. W can't just install an NPM package and
import some of its .scss files from node_modules like:

_in project/app.scss:_

@import '{}/node_modules/awesome-scss-package/scss/buttons.scss';
@import '{}/node_modules/awesome-scss-package/scss/grid.scss';

—
Reply to this email directly or view it on GitHub
https://github.com/meteor/meteor/issues/6037#issuecomment-195467736.

Hi @benjamn is there any status update on this issue?
Thanks!

This shouldn't be post 1.3, node_modules without assets is kind of useless for a fullstack solution like Meteor.

1.3 is already at RC 5, it's too late to add new features, and 1.3.1 shouldn't be too far off. In the meantime, the symbolic link workaround should be documented in the guide.

any workaround?

@infacq only workaround I've come up with was to create my own meteor package that wraps the library I want to use in my project. Then I use the api.addFiles methods to explicitly export these files out of the node_modules folder. This allows them to be imported by my app.

This is what my package.js file looks like for my foundation for apps wrapper:

Npm.depends({
  glob:'7.0.0'
});

Package.describe({
  name: 'threevl:foundation-apps',
  version: '0.0.1',
  summary: 'Builds foundation for apps into your project',
  git: 'https://github.com/3VLINC/meteor-foundation-apps'
});

Package.onUse(function(api) {

  var glob = Npm.require('glob').sync;

  api.versionsFrom('1.3-beta.11');

  api.use('fourseven:scss');

  api.use('ecmascript');

  // SCSS

  var scssFiles = glob(process.cwd() + '/packages/foundation-apps/node_modules/foundation-apps/scss/**/*.scss');

  scssFiles = scssFiles.map(function(item) {

    return item.replace(process.cwd() + '/packages/foundation-apps/','');

  });

  api.addFiles(
    scssFiles,
    'client',
    { isImport: true}
  );

});

Package.onTest(function(api) {

  api.use('ecmascript');

  api.use('fourseven:scss');  

  api.use('threevl:foundation-apps');

  api.addFiles('foundation-apps-tests.js');

});

Then in my app stylesheet I can do:

@import '{threevl:foundation-apps}/node_modules/foundation-apps/scss/foundation';

Not sure if that is workable for you, but it's done the trick for me.

just wanted to reiterate that this is definitely coming in 1.3.1

It should also work with juliancwirko:postcss (actual version for Meteor 1.3 is 1.0.0-rc.10) + postcss-import plugin.

It will work only for .css files. I'll try to play with some .scss parsers for PostCSS maybe it will be able to compile .scss files too.

So with this package you will be able to do something like:

@import 'my-awesome-lib-from-npm/styles.css';

.other-styles {
  color: red;
}

In your main.css file in the app.
The path to node_modules should be properly discovered so you don't need to add it.

@juliancwirko I can't wait to try that out.

Ok, so I have something like this: https://github.com/juliancwirko/meteor-bootstrap-postcss-test ;)

You can go through the files to see how it works.

The example uses Bootstrap 4 with Scss from Npm package. I use PostCSS plugins to compile Scss files from Bootstrap. I don't need fourseven:scss package here. And of course I can import .scss files from node_modules now.

Unfortunatelly it won't work with Foundation 6 (for now), this is because F6 uses complicated mixins structure and I can't make it work with postcss-sassy-mixins plugin :/ I'll keep trying.

Fun and weird stuff but it works for Bootstrap :D

Yikes, my first ever react component (one with a css file) import from npm and I hit this wall.

What use is the ability to import a react component from npm if that component won't look anything like it is supposed to?

Sad...

Success. I can import sass with materialize-css and node-sass using

"scripts": {
"build:css": "node-sass --include-path node_modules main.scss bundle.css"
},

in package.json where main.scss is

// paths
$roboto-font-path: "/fonts/roboto/";

// colors
@import "materialize-css/sass/components/color";
$primary-color: color("blue", "lighten-2");

// main
@import 'materialize-css/sass/materialize.scss';

For importing the behavior from materialize-css, I'm using cdn with the script at the bottom of main.html like this.


<!-- materialize-css Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.6/js/materialize.min.js"></script>

Putting the cdn in the header results in a jquery error.

Attempting to access the behavior within meteor build failed for multiple reasons.

There may be other issues since I'm just getting the boilerplate in place, but at least, the app starts using material styling and no console errors.

My testing is on Windows 10 with Meteor 1.3 with the following npm dependences

"dependencies": {
"eslint": "^2.2.0",
"eslint-config-airbnb": "^6.0.2",
"eslint-plugin-react": "^4.1.0",
"jquery": "^2.2.2",
"materialize-css": "^0.97.6",
"meteor-standalone-react-mixin": "0.0.56",
"moment": "^2.12.0",
"react": "^0.14.7",
"react-addons-pure-render-mixin": "^0.14.8",
"react-dom": "^0.14.7",
"react-router": "^2.0.0",
"react-sticky": "^3.0.0",
"tether": "^1.2.0",
"underscore": "^1.8.3"
},
"devDependencies": {
"hammerjs": "^2.0.6",
"node-sass": "^3.4.2"
}

@benjamn as _soon_ as you have a version you think you might like tested, please let us/me know and we'll jump straight on it! This is such a killer feature for React Components, as they all end up unstyled! :cry:

Also, will the fix also allow .less and .scss files to be imported?

Also, will the fix also allow .less and .scss files to be imported?

Not in the current implementation, no. The hope is that npm authors who use .less or .scss will compile them to .css files that you can import. You can also create a wrapper Meteor package that Npm.depends on the appropriate npm package, uses the less compiler plugin with api.use("less"), and calls api.addFiles to add .less files from node_modules explicitly.

@benjamn Okay, well it would have been nice to have .less & .scss support too, but it's not as urgent as the need for .css.
I guess my reason for asking was to allow NPM versions of Bootstrap / Foundation/etc to be imported, yet still have all of the mixins, which obviously the .css versions don't have.

@Siyfion You could give this a try: CSS-modules, but with a solution tailored to SCSS files. In this case react-toolbox specifically, but you might be able to hack it your way.

As a stopgap, I used this and it's working well. Install node-sass through npm and use npm scripts (or grunt or gulp) to watch and build sass files in parallel to meteor. I'm using the following in my npm scripts: node-sass --include-path node_modules --source-map true --source-map-embed true -o folder folder. This creates a file.css next to every file.scss in folder.

@benjamn

just wanted to reiterate that this is definitely coming in 1.3.1

So 1.3.1 is out, and as far as I can tell importing style assets from node_modules has been deferred to 1.3.2? What happened?

@natecox more than that, the issue is about .scss ;) and there will be only .css support for now ;) So still you won't be able to use Foundation or Bootstrap from Npm without hacks.
But I guess this isn't so important. The hacks seems to do the work.

Honestly, this really seems to defeat the point of integrating NPM in the first place. NPM is a distribution network for consolidated packages, not .js files. When you install something from NPM you expect to be able to use it as is, not piecemeal.

The solution of intentionally bypassing Meteor to side-load assets isn't a solution at all, it's just a hack.

Since the time when I promised this in 1.3.1, we've changed how we think about versioning. Releases are going to be much more frequent, and—regardless of the version number—this is coming soon. Probably exactly as soon as if we'd waited to ship 1.3.1 until this was finished.

Frequent updates are awesome, especially if they are Quality of Life upgrades. :) Thanks @benjamn

@benjamn can you clarify what the update will do exactly, when it is released?

Primarily I think this thread is interested specifically in the ability to @import 'path/to/scss' from within a base something.scss file, but the same would be true of stylus and less. Is this going to be a covered use case?

@benjamn What is the syntax for importing style.css file from node_modules package? Is it going to follow the same syntax for importing from a Meteor package:
@import "{npm-package-name}/path/to/style.css";
or relative path to node_modules:
@import "/npm-package-name/path/to/style.css";
or absolute path to node_modules:
@import "/node_modules/npm-package-name/path/to/style.css";
or something else?

I also assume we can import a directory like, please confirm.
@import "{npm-package-name}/path/to/styles/";

I'm working on some updates to Using Packages section of Meteor Guide and want to include this so we can publish when Meteor 1.3.2 is released. Thanks!

The current plan is to treat node_modules directories exactly like imports directories, from the perspective of CSS preprocessor plugins. In other words, however you would have imported a (lazy) .less or .scss file from an imports directory, you can do the same with a file contained by a node_modules directory.

This doesn't rule out the possibility that importing behavior needs to be improved in general, but I'm trying to avoid multiplying concepts, given that folks already know how imports directories work.

Does that make sense?

EDIT: Just re-read your comment and it sounds like you are planning to support CSS preprocessor plugins with this release, can you confirm? That would be really awesome.

If so, I would assume syntax would be using absolute path using the special {} syntax which represents top of you app directory:
@import "{}/node_modules/npm-package-name/path/to/style.less";
as the syntax to import from /imports is:
@import "{}/imports/path/to/style.less";

I would then assume to just import .css would be:
import '/node_modules/npm-package-name/path/to/style.css';
as you can import .css from /imports as:
import '/imports/path/to/style.css';

Also, can you do this to get all .css files in a directory?
import '/node_modules/npm-package-name/path/to/styles/';

Thanks for taking the time to answer all these questions and thanks again for all your hard work!

EDIT: Just re-read your comment and it sounds like you are planning to support CSS preprocessor plugins with this release, can you confirm? That would be really awesome.

That's right! My current implementation works without any changes to the less plugin, so I'm moderately confident any preprocessor plugin should be compatible with this implementation. I'm in the process of publishing an initial RC, but you're welcome to check out the code from https://github.com/meteor/meteor/tree/release-1.3.2 until then.

If so, I would assume syntax would be using absolute path using the special {} syntax which represents top of you app directory:
@import "{}/node_modules/npm-package-name/path/to/style.less";
as the syntax to import from /imports is:
@import "{}/imports/path/to/style.less";

That works, yes. Relative paths also work.

I would then assume to just import .css would be:
import '/node_modules/npm-package-name/path/to/style.css';
as you can import .css from /imports as:
import '/imports/path/to/style.css';

This works, but absolute paths are not necessary with import statements in JS modules. If I'm not mistaken, import "npm-package-name/path/to/style.css" will also work, as will import "npm-package-name/path/to/style.less".

Also, can you do this to get all .css files in a directory?
import '/node_modules/npm-package-name/path/to/styles/';

That's not currently supported, though you could explicitly import the styles in an index.js file in that directory to enable a similar effect.

Thanks for taking the time to answer all these questions and thanks again for all your hard work!

Thanks for your feedback and patience! I hope this solves some of your problems.

I can confirm that the behavior of fourseven:scss is identical to less (= changes that work for the less pacakge should theoretically also work for scss). Except for absolute paths, since it was never really clear to me how to deal with them. But if the behavior for absolute paths is defined, it should be easy to make fourseven:scss compliant.

When my main .scss file is in for example /client folder It seems that only @import '../node_modules/path/file.scss' works for me. (Meteor v1.3.2-rc.0)

edit: it works with @import '{}/node_modules/foundation-sites/scss/foundation.scss'; my bad.

It would be awesome if we could import it by @import 'foundation-sites/scss/foundation.scss' ;)

Here is my little test: https://github.com/juliancwirko/meteor-npm-foundation-test

@benjamn Awesome work! You said you thought
import 'npm-package-name/path/to/style.less';
would work from a JS file using ES6 import like you can do with a plain .css file. I'm not clear how this would be picked up by the CSS pre-processor.

Also, it would be awesome to be able to also use the syntax @juliancwirko mentioned for when importing from another style file
@import 'npm-package-name/path/to/style.less';
or even
@import '{npm-package-name}/path/to/style.less';
but maybe that would create an inconsistency with how the pre-processors work with /imports and/or create conflicts with Meteor package imports.

I just updated to 1.3.2-rc.1 and noticed that the new way of using @import did not work as I expected.

Here's what I write in /imports/ui/components/my_component.less:

@import '{}/node_modules/module_name/dist/module_name.css';
.selector {
  // 
}

Here is what I see in the browser:

Resource interpreted as Stylesheet but transferred with MIME type text/html:
"http://localhost:3000/%7B%7D/node_modules/module_name/dist/module_name.css".

Looks like @import for pure css is treated differently compared to less files – in that case I'd get a build error. How can one disable this behaviour and import .css files from node_modules just as if they were .less?

@kachkaev Tbh, I tried running 1.3.2-rc.1 and my app wouldn't even start-up, so count yourself lucky! lol.

@kachkaev for better or worse, that's how LESS is supposed to work: http://lesscss.org/features/#import-directives-feature-file-extensions

According to the section below that, the following import style might work for you:

@import (less) '{}/node_modules/module_name/dist/module_name.css';

Good point @benjamn, I did not know about this peculiarity of less. Your suggestion did not work though – after changing the import the way you say I got a good old error message in the terminal:

=> Errors prevented startup:

   While processing files with less (for target web.browser):
   imports/ui/components/my_component.less:1: Unknown import:
{}/node_modules/module_name/dist/module_name.css

I'm pretty sure the path has no typos.

Interestingly, any less imports from, let's say, {}/imports directory that stand nearby work well. This is Meteor 1.3.2-rc.1, launched from scratch (after updating from 1.3.1 and then deleting .meteor/local directory).

What could go wrong?

Whatever we decide, we must not forget that other node modules must be able to import their dependencies successfully too. So for example a module may have a dependency on font-awesome it needs to be able to do @import "../node_modules/font-awesome/less/fa.less" from within another module.

@georget-ocado That will work as long as the parent module contains any .less files. Once we find an npm package that does not contain any style files, we avoid scanning its node_modules directory. For most npm packages, this means the scanning stops very quickly, without traversing deeply nested node_modules directories.

Note that 1.3.2 RC1 breaks apps build with webpack:webpack.
For instance:

git clone https://github.com/thereactivestack/kickstart-meteor-react.git
cd kickstart-meteor-react/
meteor update
meteor
npm install
meteor

works OK.

But if I do

meteor update --release 1.3.2-rc.1
meteor

I get

[[[[[ ~/meteor/debug/kickstart-meteor-react ]]]]]

=> Started proxy.                             
=> Started MongoDB.                           
webpack built e3e07b965296f735f4f8 in 1493ms /
Hash: e3e07b965296f735f4f8
Version: webpack 1.12.14
Time: 1493ms
 Asset    Size  Chunks       Chunk Names
web.js  222 kB       0       main
chunk    {0} web.js (main) 77.8 kB [rendered]
    [0] multi main 40 bytes {0} [built]
    [1] ./~/webpack-hot-middleware/client.js?path=http://localhost:3500/__webpack_hmr 4.18 kB {0} [built]
    [2] (webpack)/buildin/module.js 251 bytes {0} [built]
    [3] ./~/querystring/index.js 127 bytes {0} [built]
    [4] ./~/querystring/decode.js 2.4 kB {0} [built]
    [5] ./~/querystring/encode.js 2.09 kB {0} [built]
    [6] ./~/strip-ansi/index.js 161 bytes {0} [built]
    [7] ./~/ansi-regex/index.js 135 bytes {0} [built]
    [8] ./~/webpack-hot-middleware/client-overlay.js 1.73 kB {0} [built]
    [9] ./~/ansi-html/index.js 4.02 kB {0} [built]
   [10] ./~/html-entities/index.js 231 bytes {0} [built]
   [11] ./~/html-entities/lib/xml-entities.js 2.98 kB {0} [built]
   [12] ./~/html-entities/lib/html4-entities.js 6.57 kB {0} [built]
   [13] ./~/html-entities/lib/html5-entities.js 49 kB {0} [built]
   [14] ./~/webpack-hot-middleware/process-update.js 3.88 kB {0} [built]
   [15] ./src/client.js 41 bytes {0} [built] [1 error]

ERROR in ./src/client.js
Module not found: Error: Cannot resolve module 'TodoApp/client' in /home/laurent/meteor/debug/kickstart-meteor-react/src
 @ ./src/client.js 3:0-25
=> Errors prevented startup:                  

   While processing files with webpack:webpack (for target os.linux.x86_64):
   src/server.js: ./src/server.js
   Module not found: Error: Cannot resolve module 'TodoApp/server' in /home/laurent/meteor/debug/kickstart-meteor-react/src
   resolve module TodoApp/server in /home/laurent/meteor/debug/kickstart-meteor-react/src
   looking for modules in /home/laurent/meteor/debug/kickstart-meteor-react/node_modules
   /home/laurent/meteor/debug/kickstart-meteor-react/node_modules/TodoApp doesn't exist (module as directory)
   [/home/laurent/meteor/debug/kickstart-meteor-react/node_modules/TodoApp]
   @ ./src/server.js 3:0-25

=> Your application has errors. Waiting for file change.

@laurentpayot can you file that as a separate issue? I don't think it has anything to do with importing styles…

@benjamn sure: #6787

Though there is more work to do on the individual plugin packages re: import path syntax, the core meteor-tool support seems to be in place, and will be released with Meteor 1.3.2 this Friday. You can test it out by doing meteor update --release 1.3.2-rc.5 now. Thanks for your feedback, everyone!

Great job @benjamn

It would be helpful if there was documentation as how to include Bootstrap from NPM. I'm sure this will be a hotly requested question (including from me :smile:)

I agree with @sys13. Trying the following after upgrading to 1.3.2-rc.5 from a .less file, no luck:

@import (less) '{}/node_modules/module_name/dist/module_name.css';
@import (less) '/node_modules/module_name/dist/module_name.css';
@import (less) '{module_name}/dist/module_name.css';
@import (less) '../../../../node_modules/module_name/dist/module_name.css';

Error message in the console says:

Errors prevented startup:                  

   While processing files with less (for target web.browser):
   ***/my_file.less:1 Unknown import: ***/module_name.css

@sys13 Agreed about the need for documentation, though I will mention that importing Bootstrap from npm via JS works:

meteor create test-app
cd test-app
meteor npm install --save bootstrap
echo 'import "bootstrap/dist/css/bootstrap.css";' >> client/main.js
meteor run

@kachkaev The same trick may work for you: instead of importing the .css file from a .less file, import both from a JS file?

I prototyped an implementation that extracts @import "path/to/file.css" statements and turns them into require("./path/to/file.css") calls when converting the CSS file to CommonJS. I rolled it back because it felt like I was solving problems for the less plugin that it could solve for itself, though I'm open to reconsidering that decision.

@benjamn I moved the import to /imports/ui/components/MyComponent.jsx and surprisingly the trick worked:

@import 'module_name/dist/module_name.css';

It's feels bit strange to import a css in a js file, but this is still better than creating symlinks for each case. Thank you.

@benjamn Being able to import into sass/stylus/less is important because many systems (including bootstrap) are designed around setting style variables which update groups of styles at a time. E.g., setting gutter padding via a single variable across many components.

Looking forward to trying this out when I get the opportunity.

@sys13 I have two example repos with some tips in the readme ;)
Foundation 6: https://github.com/juliancwirko/meteor-npm-foundation-test
Bootstrap 4: https://github.com/juliancwirko/meteor-bootstrap-npm-test

Finally we can use these frameworks like we should ;)

@natecox Importing .less files into other .less files works (same for scss, sass, etc.); the issue discussed above is just that LESS generates CSS @import statements to import plain .css files. Plain .css files don't export or consume any variables or mixins, so I don't think the use cases you're describing are threatened by this problem.

I have weird path issues when importing semantic-ui-less styles from node modules, in webpack:webpack apps as well as with "normal install" apps.

  • With webpack:
git clone https://github.com/thereactivestack/kickstart-meteor-react.git
cd kickstart-meteor-react/
meteor update --release 1.3.2-rc.5
meteor update
npm install semantic-ui-less --save
meteor add webpack:less
mv node_modules/semantic-ui-less/theme.config.example node_modules/semantic-ui-less/theme.config
mv node_modules/semantic-ui-less/_site/ node_modules/semantic-ui-less/site
echo "import '../node_modules/semantic-ui-less/semantic.less';" >> src/client.js 
meteor
npm install
meteor

I get many duplicated folder path errors (note the ./themes/themes/) like:

ERROR in ./~/css-loader?{"localIdentName":"[name]__[local]__[hash:base64:5]"}!./~/less-loader!./~/semantic-ui-less/semantic.less
Module not found: Error: Cannot resolve 'file' or 'directory' ./themes/themes/default/assets/fonts/icons.eot in /home/laurent/meteor/debug2/kickstart-meteor-react/node_modules/semantic-ui-less
 @ ./~/css-loader?{"localIdentName":"[name]__[local]__[hash:base64:5]"}!./~/less-loader!./~/semantic-ui-less/semantic.less 6:279304-279361 6:279384-279441

A dirty fix was to create a symbolic link and then everything works perfectly:

cd node_modules/semantic-ui-less/themes/
mkdir themes
cd themes/
ln -s ../default/
  • With "normal install" apps:
git clone https://github.com/meteor/simple-todos.git
cd simple-todos/
meteor update --release 1.3.2-rc.5
meteor update
npm install semantic-ui-less
mv node_modules/semantic-ui-less/theme.config.example node_modules/semantic-ui-less/theme.config
mv node_modules/semantic-ui-less/_site/ node_modules/semantic-ui-less/site
echo "import '../node_modules/semantic-ui-less/semantic.less';" >> client/main.js
meteor add flemay:less-autoprefixer
meteor

I get:

=> Errors prevented startup: 
   While building for web.browser:
   node_modules/semantic-ui-less/definitions/globals/reset.less:19: Unknown import: ../../theme.config
=> Your application has errors. Waiting for file change.

I don't think that's a bug on Semantic UI side because it would have been known for a while. Especially if MDG is playing with style files imports from node modules at the moment...

Same with 1.3.2 brand new release.

@laurentpayot It looks like that theme.config file is meant to be a .less file but doesn't have a .less file extension. You need a Meteor compiler plugin that handles the .config file extension for that file to be importable.

You might be able to get it to work by installing the less plugin locally and adding .config as a file extension here.

Thanks @benjamn , well the symbolic link trick fixed it for webpack so it's weird but working…

Are there any docs on this feature? In particular:

  • Where can I place this import? Does it go in a JavaScript module, in a .css file, or do I have to use a CSS preprocessor?
  • Is the format "{}/node_modules/toastr/build/toastr.css", "{}toastr/build/toastr.css" or something else?

Thus far I've tried importing this in a JS module (I.e. import "{}...") and am told the module can't be found. I've also tried various permutations of the path using the CSS @import directive in my CSS stylesheet. Feel free to point me to docs if they exist, I just glanced at the diff but don't know enough about how the build system works to determine usage from that. I've also read this blog post but it isn't clear from that where the import can go.

Thanks!

I've got an open PR to get info on using imports with node_modules into the Meteor Guide. https://github.com/meteor/meteor/issues/6037#issuecomment-211452834

I think it may be waiting on final validation that all of these work, but give it a try:

Importing styles from npm

Using any of Meteor's supported CSS pre-processors you can import other style files from both relative and absolute paths from an npm package.

Importing styles from an npm package with an absolute path using the {} syntax:

@import '{}/node_modules/npm-package-name/button.less';

Importing styles from an npm package with a relative path:

@import '../../node_modules/npm-package-name/colors.less';

Importing CSS from an npm package from another style file;

@import 'npm-package-name/stylesheets/styles.css';

You can also import CSS directly from a JavaScript file to control load order if you have the ecmascript package installed.

Importing CSS from an npm package in a JavaScript file using ES2015 import;

import 'npm-package-name/stylesheets/styles.css';

EDIT: As mentioned, when importing from JS the CSS is put in the <head> tag like <style>...</style> after the main concatenated CSS file.

I've just been trying all day to make this work, and after installing fourseven, I could successfully load scss from external packages inside an atmosphere package.
However, I'm not able to load CSS from another CSS with imports, only from JS (and I can't use that because of load order problems with the css loaded in the head from the eagerly load code).
Is this supposed to work? or only importing CSS from JS is supported ?

So if I have the toastr NPM package, which provides
toastr/build/toastr.css, I should be able to put:

@import "toastr/build/toastr.css"

in client/modules/core/stylesheet.css to have it imported? Or do I
specifically have to use a stylesheet preprocessor?

I'm thinking the docs mean to imply this won't work from vanilla CSS. I
can't tell whether they mean to say that I can import CSS that I have a
preprocessor for, or if I need a preprocessor to handle the NPM imports.
I'd like to pull this into my CSS stylesheet since I don't know how it
might work should I decide to switch my client-side JS to TypeScript or
something else.

According to @skirunman CSS imports from other CSS files should work. Right now, for me it works if I do
import "toastr/build/toastr.css" from a js file (or a require), but not If I do an import from CSS files. I'm opening a new issue to clarify the behaviour #6846

Interesting, if I do:

import "{}/node_modules/toastr/build/toastr.css"

I'm told:

Unable to resolve some modules:

   "{}/node_modules/toastr/build/toastr.css" in
/home/nolan/Projects/Perceptron/App/client/modules/core/index.js 
(web.browser)

If you notice problems related to these missing modules, consider running:

   meteor npm install --save {}

What am I getting wrong?

Oops my bad try with import "toastr/build/toastr.css" inside your JS file, this is how it works for me

Huh, OK. Should this place the CSS in merged-stylesheets.css or
somewhere else? I no longer get the warning about missing imports but I
don't see the styles in merged-stylesheets.css either.

Thanks.

@ndarilek it will just attach contentes to the <head> tag like <style>...</style>.

I've played with this functionality to achieve CSS Modules ;) https://github.com/juliancwirko/meteor-css-modules-test

No, it won't be in your merged stylesheets, but will end in your app.js code, which will insert it in in your head between <style></style> (AFTER the merged_stylesheets.css) that's one of the problems for me.(i wish it was beforethe merged_stylesheets.css)

Ah, so it is. Thanks for all the clarifications. If there's an issue
opened for the @import case for plain CSS stylesheets then do let me
know. I'm a bit worried about what will happen if I refactor this
client-side code to TypeScript and it tries to validate my CSS import.

Thanks.

I have created and updated the post https://github.com/meteor/meteor/issues/6846

@tcastelli OK, I'm confused. Are you trying to import a .css file that is located inside an npm package, i.e. inside node_modules/some-package or from inside a Meteor Atmosphere package? To my understanding you don't need to (and can't) import CSS files from an Atmosphere package because CSS files in an Atmosphere package are declared with api.addFiles, and therefore will be eagerly evaluated, and automatically bundled with all the other CSS in your app.

You can lazily load certain Less, Sass, or Stylus files from an Atmosphere package, but those files have to be marked as 'import' files so they are not eagerly evaluated by Meteor and the CSS Pre-processor you are using.

What I was discussing earlier is how to import CSS from an npm package. I also commented on #6846.

Also, it would help if people would read and comment on these changes to the Using Packages section of the Meteor Guide I reference in this PR https://github.com/meteor/guide/pull/365. I'm trying to get this PR pushed by MDG ASAP, but it needs some checking I'm sure.

I want to import from a npm package like {}/node_modules/bootstrap/css/bootstrap.css or whatever, sorry if I was not clear enough(also posted a reply on my issue)

@benjamn I feel like @tcastelli is asking what will probably be a very common question; it would probably be helpful to document the answer somewhere official and easily accessed.

@tcastelli For what it's worth, I would typically import bootstrap (or any other library which distributes sass assets) from within a local main sass file. The main reason for this being that it is generally very easy to make global overrides via exposed sass variables. If you really want to just import the .css file you should probably do it from within a javascript import as discussed above.

That's exactly how I have solved the problem with bootstrap and font-awesome and other libraries exposing theis sass (since with fourseven, importing scss works perfectly), but for npm packages that don't expose their scss and give only css files, I feel like import should also work inside normal css files.

I agree that it makes more sense to import .scss files from Bootstrap so you can just load what you want.

I think you tried this and it does not work, which is expected:

// import from some .css file in my app
@import '{}/node_modules/ npm-package-name/stylesheets/styles.css';

Did you try as this as this is what I would expect to work:

// import from some .css file in my app
@import 'npm-package-name/stylesheets/styles.css';

I have tried both ways and it doesn't work for me at least. Also, I've just discovered that the error I was getting on #6846 dissapears if after a "@import "font-awesome/css/font-awesome.css"; i place something like .blablabla{}; otherwise it complains about incorrect import. In any case, then the broswers shows this

Trying to load http://localhost:3000/font-awesome/css/font-awesome.css

which is not the correct path so it doesn't find it.

If the second option above does not work then I think maybe it would make sense to focus the conversation on your #6846 and see if we can get this fixed or implemented as a new feature.

@benjamn I like @thatgibbyguy's suggestion, relative to the app root, but absolute paths could point anywhere:

{
  "includePaths": [
    "node_modules/some/path/"
  ]
}

Are you guys averse to allowing some sort of configuration like this?

Hi,
try to setup meteor 1.3.2.4 and react
when just doing an import "/font-awesome/css/font-awesome.css"; in my jsx file i see when debugging in the browser there is a section in the indicating awesome as text/css style. (like bootstap) However the fonts are not found. Something wrong with path's? I also see path indicating ../fonts, and read something about fa-font-path but don't see a way out.

@wimvanloocke importing .css file in .js file adds the contents of that .css file to the <head> so you probably need to put your font files in /public/fonts folder and change the font path in .css file to the /fonts. Anyway I wonder if this is a way to go, maybe it will be simpler to just place font-awesome.css file outside the imports folder or just use CDN for that. You can also use .scss or .less version of font-awesome and import it in your .less or .scss files instead in .js file.

Maybe your right but i don't want to mess up and use a lot of different methods. Why does it work for imports of bootstrap, adminlte,.. and not for font-awesome,... do i miss an import / dependency. Is font-awesome not "build" for using this way?

If you place the font files in public/fonts and the library that you want to use is using an absolute route like@import /fonts/xxxxx.wotf for example, it can work(assuming that you copy the fonts files to your public folder).Otherwise, If the library is looking for the file with a relative path like @import ../fonts/xxxx.wotf, then it won't work, since the final route doesn't match where you have placed the fonts and there are there are a few solutions for that.

  • Modify the original css changing every import and changing ../fonts for /fonts and place the new css file inside your code normally-> Pain to keep updated but fast and easy
  • Import all css from CDN in your <head> </head>. This is quite useful if you don't have load order problems but remember the final code will have 1st merged styles from your css/atmosphere packages, 2nd those from CDN and 3rd the ones imported through javascript. If you are mixing different sources this can be a pain in the... to control, but if you can load all your css from CDN then it is easy to control the load order and really fast(as long as there aren't hundreds of css files/files to load)
  • Import everything with the package mizzao:build-fetcher or similar. This is a not so common use, but will allow you to place the css files and font files in the correct folders and all the css will be placed in your merged stylesheets(so at the beginning of everything). -> This is not as fast as using CDN because you serve the content, but it helps to get everything on its place, and is also not hard to update. However, you can't check for dependencies or updates automatically (which is handy is you use npm)

So basically, there's no easy way right now to import source files from npm packages that involve css and font files (or something different than less, sass or stylus), especially when they are using relative paths on @imports. In those cases, atmosphere packages like meteor add tws:bootstrap or the previous solutions can help until we have a native feature for that (hopefully soon)

If you have sym links to npm's font folders in the public folder, then meteor would not serve any static files (img & fonts) under public. May be a bug?

You have to copy the npm's fonts folder to public & have it referenced as /fonts to work.
It's just painful & maintenance nightmare.
BTW, I am on 1.3.2.4

@benjamn I'm not sure this issue should be closed. From what I understand you closed this because meteor now allows importing css files via javascript into <head>. Is this really the best practice solution?

To me it feels like a hack at best and not a great developer experience (why import all of our styles in main.less except some random npm package's css?) It also seems like we're missing out on the possibility to see unminified CSS in development and still have the css bundled and minified in production.

Still getting:

=> Errors prevented startup:

   While processing files with less (for target web.browser):
   client/main.less:8: Unknown import: {}/node_modules/zoaui/css/form.css

=> Your application has errors. Waiting for file change.

Edit:import 'react-bootstrap-table/css/react-bootstrap-table.css'; seems to work from the jsx file, which is good enough for me. However, I was definitely not able to import it from css... (tried all permutations from here https://github.com/meteor/meteor/issues/6037#issuecomment-211467837)

Anyone fix this? I'm on 1.4.2.3 and importing css files doesn't work from node_modules(I'm not talking less or sass). I was convinced I was doing something wrong, so I copied the file to my own file and, magic, it works :(

But I'm trying to use bootstrap, and copying all stylesheets kind of defeats the purpose. Am I doing something wrong and y'all fixed it? Should I do a package.js file? This is my absolute first app and I seriously have no idea what I'm doing...

Haven't found a solution to importing a .css file through another CSS file. I'm not happy either about having to import it via a JS file.

is this feature (import css from node modules) implemented in any release of meteor?

OK, so what's the TL;DR two years later? How can I import a .CSS file from an npm package? Is it only possible via JS while #6846 is getting fixed?

@dandv - yes with 1.6 it's much easier. I've recently started playing around with it and I'll show you how it's done.

After updating meteor meteor update you can import like so:

@import "{}/node_modules/plygrid/src/scss/_ply.scss";

Simple as that. (note, this is with the latest fourseven:scss)

@thatgibbyguy: I'm on Meteor 1.6.1 and I've meteor npm installed rmwc.

Added this to client/main.css but in DevTools I see that meteor serves / instead of the CSS:

@import '{}/node_modules/material-components-web/dist/material-components-web.css';

If I add this to main.js, the CSS does load:

import 'material-components-web/dist/material-components-web.css';

I'm also importing in the main.js.

@dandv have you tried with postcss? https://github.com/meteor/meteor/issues/6846#issuecomment-336233084

It has not yet been solved completely but seems to help in some cases.

They migrated this to the feature request repository now: https://github.com/meteor/meteor-feature-requests/issues/278

I made a PR with CSS imports working with POSTCSS in this Meteor React boilerplate from @juliancwirko. If you're having trouble making it work, take a look. It has the SCSS preprocessor working along with the POSTCSS as well.
https://github.com/juliancwirko/scotty

I've tried every option and workaround on this thread and nothing ain't working. Seems like a whole pile of doggy doo to me, npm packages from all over incorporate their own css which you need to import (and yes I mean css, not scss), and yet it seems MDG have ignored it despite getting all excited about whether it would make version 1.3 or have to wait until the first patch two-and-a-half years ago ??!

@andrewlorenz I've got it working just fine. Here's what I've got:

  • Meteor 1.7.0.3
  • fourseven:scss (latest)
  • plygrid (npm install plygrid)

In /client/css/main.scss :

@import "{}/node_modules/plygrid/src/scss/_ply.scss";

Of course you may be using vanilla css and I wouldn't know how to incorporate that other than putting it in public and just writing vanilla css in client. Seems like you could have two working options here.

Hi all, please see @livimonte 's comment above. For vanilla CSS, not SCSS or LESS, you should import it from your node_modules by in your ./client/ js source.

Here's an example of a ./client/main.js using the npm package materialize-css -

import 'materialize-css/dist/js/materialize.min';  // omit the .js
import 'materialize-css/dist/css/materialize.min.css';  // non-js imports have the extension

Using @import url() in your main.css doesn't work for node_modules sources, because that usage depends on installing a third party pre-processor. Instead, just import it directly into a client JS file and ecmascript figures it out.

Please do some research before spamming the issue boards, it's even in the official guide!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

damjuve picture damjuve  Â·  101Comments

giacecco picture giacecco  Â·  80Comments

KoenLav picture KoenLav  Â·  120Comments

EliArtist picture EliArtist  Â·  134Comments

Jayuda picture Jayuda  Â·  85Comments