Skip to content

Is there a proper way to import vendor styles from a CSS module? #253

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

Closed
dbazile opened this issue Apr 6, 2016 · 15 comments
Closed

Is there a proper way to import vendor styles from a CSS module? #253

dbazile opened this issue Apr 6, 2016 · 15 comments

Comments

@dbazile
Copy link

dbazile commented Apr 6, 2016

Are any of the following intended to work?

@import "leaflet/dist/leaflet.css";
    // throws `Error: Cannot resolve module 'images/layers.png'`

:global { @import "leaflet/dist/leaflet.css"; }
    // throws `Error: Cannot resolve module 'images/layers.png'`

:global { @import '../../node_modules/leaflet/dist/leaflet.css'; }
    // throws `Error: Cannot resolve module 'images/layers.png'`

:global { @import '!style!css?-module!leaflet/dist/leaflet.css'; }
    // throws `CSSSyntaxError
    //   @ ./~/css-loader?module&localIdentName=[name]__[local]!./~/less-loader!./app/components/MapWidget.less 3:10-138`

Background

I'm trying to load the vendor CSS from Leaflet and running into errors because it does relative imports for image assets. What I'd like to have happen is the CSS is loaded and everything in it treated as a global.

I've been scouring the web for a few hours now and couldn't find an answer to this.

Temporary Workaround

I've disabled modules on plain .css files and added import 'leaflet/dist/leaflet.css'; to the top of the .jsx file. Is this the happy path? It's certainly the path of least resistance, but it feels odd to have this thing dangling outside of CSS.

My guess as to what's happening

My guess is the CSS loader is preempting the LESS loader and doesn't recognize the :global {} nesting.

Relevant parts of webpack.config.js:

module.exports = {
  context: path.join(__dirname, 'app'),
  entry: './index.js',
  devtool: 'source-map',

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

  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
  },

  module: {
    preLoaders: [
      {test: /\.jsx?$/, loader: 'eslint', exclude: /node_modules/}
    ],
    loaders: [
      {test: /\.jsx?$/, loader: 'babel', exclude: /node_modules/},
      {test: /\.css$/, loader: 'style!css'},
      {test: /\.less$/, loader: 'style!css?module&localIdentName=[name]__[local]!less'},
      {test: /\.(png|jpg|gif)$/, loader: 'file'}
    ]
  },

  plugins: [
    new webpack.EnvironmentPlugin(['NODE_ENV']),
    new HtmlWebpackPlugin({
      title: `${pkg.name} v${pkg.version}`,
      hash: true,
      xhtml: true
    }),

    // Polyfill just in case -- unsure what cutoff is for "modern browsers"
    new webpack.ProvidePlugin({fetch:'isomorphic-fetch'})
  ]
};
@psimyn
Copy link

psimyn commented Apr 14, 2016

I think one of your first 2 options is the way to go. Going off less-loader readme adding a ~ to the import statement should make it look in node modules directory. You will want to use less-loader for this though (both css/less files processed by less-loader in webpack.config)

then try (maybe)

@import "~leaflet/dist/leaflet.css";

I think imports remain unchanged, css-modules uses composes for transforming imports. May be way off though

@stigi
Copy link

stigi commented Sep 28, 2016

@dbazile any luck so far? I'm still struggling with this. I don't really want to add less-loader since I'm only dealing with plain css in my project.

@stigi
Copy link

stigi commented Sep 28, 2016

For added context, here's what I did so far:

Added to webpack.config.js

  resolve: {
    extensions: ['', '.html', '.js', '.json', '.scss', '.css'],
    alias: {
      leaflet_css: __dirname + "/node_modules/leaflet/dist/leaflet.css"
    }
  }

I also add images via url-loader

{ test: /\.(png|jpg|jpeg|gif|woff)$/, loader: 'url-loader?limit=8192' },

And then imported it together with leaflet and react-leaflet

import 'leaflet'
import 'leaflet_css'
import { Map, TileLayer, LayersControl, ScaleControl, Marker, Popup } from 'react-leaflet'

The errors I'm seeing are

ERROR in ./~/css-loader!./~/leaflet/dist/leaflet.css
Module not found: Error: Cannot resolve directory './images' in /Users/ullrich/projects/cruisejs/node_modules/leaflet/dist
 @ ./~/css-loader!./~/leaflet/dist/leaflet.css 6:9471-9491

ERROR in ./~/css-loader!./~/leaflet/dist/leaflet.css
Module not found: Error: Cannot resolve module 'url-loader' in /Users/ullrich/projects/cruisejs/node_modules/leaflet/dist
 @ ./~/css-loader!./~/leaflet/dist/leaflet.css 6:8253-8283

ERROR in ./~/css-loader!./~/leaflet/dist/leaflet.css
Module not found: Error: Cannot resolve module 'url-loader' in /Users/ullrich/projects/cruisejs/node_modules/leaflet/dist
 @ ./~/css-loader!./~/leaflet/dist/leaflet.css 6:8417-8450

@Tortel
Copy link

Tortel commented Sep 28, 2016

The './images' directory error is caused by this line:
https://github.com/Leaflet/Leaflet/blob/v1.0.0/dist/leaflet.css#L379

For convenience, this is the commit that added this line:
https://github.com/Leaflet/Leaflet/blob/v1.0.0/dist/leaflet.css#L379

@Tortel
Copy link

Tortel commented Sep 28, 2016

Theres an issue open under leaflet about this too:
Leaflet/Leaflet#4849

@dbazile
Copy link
Author

dbazile commented Sep 29, 2016

@stigi: Haven't tried in a while. My temporary workaround has since evolved into a permanent workaround; I just require the vendor CSS in the .JSX file which sidesteps the module scoping.

@gnarf
Copy link

gnarf commented Oct 12, 2016

Haven't tried in a while. My temporary workaround has since evolved into a permanent workaround

Same, but it would be nice if :global @import could work tho right?

@dbazile
Copy link
Author

dbazile commented Oct 12, 2016

@gnarf: That syntax looks like it might lead down a dark path. :D

IMO, it should work such that the idiomatic Webpack way works, i.e., @import "!style!css!~leaflet/dist/leaflet.css"; avoids modularizing the imported style sheet. It may well be the case now; I don't have to same configuration anymore so I can't easily check.

@sunny-g
Copy link

sunny-g commented Oct 31, 2016

Adding css?url=false to your CSS loader's config gets rid of the issue (with the side effect of disabling any URL parsing in your CSS, which in my case isn't a problem).

Another potential solution is to use css-raw-loader only on leaflet.css to import it without running it through your CSS loader.

@hinok
Copy link

hinok commented Jan 26, 2017

I have the same problem...

ERROR in ./~/css-loader?{"localIdentName":"[path]---[name]---[local]","modules":false,"importLoaders":1,"sourceMap":true,"minimize":false,"discardComments":{"removeAll":true}}!./~/postcss-loader?{"sourceMap":true}!./~/sass-loader?{"sourceMap":true}!./src/components/Map/styles.global.scss
Module not found: Error: Can't resolve './images/layers-2x.png' in '/Users/user/Desktop/Dev/project/src/components/Map'
 @ ./~/css-loader?{"localIdentName":"[path]---[name]---[local]","modules":false,"importLoaders":1,"sourceMap":true,"minimize":false,"discardComments":{"removeAll":true}}!./~/postcss-loader?{"sourceMap":true}!./~/sass-loader?{"sourceMap":true}!./src/components/Map/styles.global.scss 6:7558-7591
Can't resolve './images/layers-2x.png'

The only way to easily fix it is by disabling url only for leaflet like @sunny-g said.
It's not a big deal in this case because leaflet has API that allows for defining urls for images
PaulLeCam/react-leaflet#255 (comment) but a lot of other packages don't expose such API.

Two weeks ago the same problem was reported on official css-modules repo -
css-modules/css-modules#205

Could someone explain what is the expected behaviour here? It seems a bit strange for me that scss / css files in node_modules cannot reference any images with relative paths...

@joshwiens joshwiens removed the question label May 1, 2017
@Origslammer1
Copy link

Solved: Had similar problem needed to to import bootstrap template into css from scss see below:
@import "vendors/_bootstrap.scss";
body{
padding-bottom:50px;
}
The folder vendors has to be in the same directory as the scss file for it to work

@besh
Copy link

besh commented Jan 16, 2018

@Origslammer1 while that solution works, what happens when bootstrap updates? The real solution needs to address installed node modules.

@alexander-akait
Copy link
Member

Sorry for delay! PR welcome!

@alexander-akait
Copy link
Member

Not related to css-loader please create issue with feature request in https://github.com/css-modules/postcss-modules, thanks!

@ranrolls
Copy link

Everything is working if we use following

https://stackoverflow.com/questions/41368263/how-to-import-external-scss-properly-with-webpack-and-vue-js

Thanks 22samuelk

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