npm packages can't call require() on css files.
Closed this issue · 5 comments
Calling require() on a css file in an npm package doesn't seem to correctly load it as a CSS file. It gets required() as a javascript file and throws an error.
Steps to reproduce
I created a js file in node_modules/testmodule/index.js.
index.js
require("./test.css");
test.css
.testclass {
}
app/main/components/Home.js
/* @flow */
import React, { Component } from "react";
import "./Home.scss";
import 'testmodule/index.js';
export default class Home extends Component {
render () {
return (
...
testapp/app/testapp/node_modules/testmodule/test.css:1
(function (exports, require, module, __filename, __dirname) { .testclass {
^
SyntaxError: Unexpected token .
at createScript (vm.js:74:10)
at Object.runInThisContext (vm.js:116:10)
at Module._compile (module.js:533:28)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Module.require (module.js:513:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (testapp/node_modules/testmodule/index.js:1:63)
Typically files imported inside of node_modules are handled differently to those imported as part of your application. If you want the code inside of a node_modules folder to not be treated as 3rd party code where webpack loaders do not apply you need to whitelist the folder for testmodule.
You can update how the webpack config works using GlueStick hooks to treat your 3rd party module as application code. Here is an example of how that is done:
webpackClientConfig: [config => {
const jsRule = config.module.rules.find(rule => rule.test.source.includes("js"));
jsRule.include = [
/src/,
/gluestick/,
/node_modules\/testmodule/
];
delete jsRule.exclude;
return config;
}],
This would be done in src/webpack.hooks.js. You can find documentation for this here: https://github.com/TrueCar/gluestick/blob/next/docs/configuration/CachingAndHooks.md#hooks
What you are trying to do is possible but it's not very common, that is why it is a little difficult. However, if you have any ideas on how to make something like this more simple or feel this is more common that I believe let me know that as well. Would be open to a pull request that makes this type of behavior easier.
The reason I encountered this issue is because a third party react component npm package caused this error, and it had previously worked on an earlier version of gluestick. Is it not common for react components to use CSS or SCSS files?
Additionally, if the file is required() from the client and not the server, it works:
Home.js
componentDidMount() {
require('testmodule/index.js');
}
Is it intended that on the client side the node_modules files are run through the webpack loaders?
I applied
webpackClientConfig: [config => {
const jsRule = config.module.rules.find(rule => rule.test.source.includes("js"));
jsRule.include = [
/src/,
/gluestick/,
/node_modules\/testmodule/
];
delete jsRule.exclude;
return config;
}],
But it didn't seem to work. I applied it to both server and client configs.
I've also white-listed everything inside the app folder "testapp" and it runs unless I import the testmodule.
include = [
// /src/,
// /gluestick/,
// /node_modules\/testmodule/,
/testapp/
];
So it doesn't seem like it's an issue with the js loader.
My temporary workaround is sym-linking the node_modules folder of affected packages from within my src folder.
Also importing from "../../../../node_modules/" also works.
Based on the above it doesn't even seem like the webpack loaders are the issue since whitelisting them doesn't work. Perhaps some other part is blocking proper loading of node_modules?
Multiple npm packages I import are affected by this—basically anything that has its own CSS files.
Found the issue in the docs:
compiled - path to node_modules module which needs to be parsed by webpack loaders (by default all modules from node_modules will be marked as external in server bundle, which means they won't be parsed by loaders, so in case you need the module to be transpiled or if it's a css/scss file you need to prefix it with this alias eg: import 'compiled/normalize.css')
So by prepending "compiled" as in require('compiled/testmodule/index.js');
will work.