rails / webpacker

Use Webpack to manage app-like JavaScript modules in Rails
MIT License
5.31k stars 1.47k forks source link

Import CSS from JS file not working in production #2667

Closed randall-coding closed 3 years ago

randall-coding commented 4 years ago

I have react components that are loading css directly into the component as described in your notes here https://github.com/rails/webpacker/blob/master/docs/css.md. Below is a snippet of my code.

import './Messenger.css';
import './index.css';
import $ from 'jquery';

class Messenger extends React.Component{
    constructor(props){
      super(props)

That loads my styles fine in development mode, but not in production. The HTML is there but unstyled and there are no js errors in console.

This is my package.json file

{
  "name": "startup_happy",
  "private": true,
  "dependencies": {
    "@babel/preset-react": "^7.7.0",
    "@material-ui/core": "^4.6.0",
    "@rails/webpacker": "^4.2.2",
    "@stripe/react-stripe-js": "^1.0.3",
    "@stripe/stripe-js": "^1.0.2",
    "@vimeo/player": "^2.12.0",
    "axios": "^0.19.2",
    "babel-plugin-transform-react-remove-prop-types": "^0.4.24",
    "grunt": "^1.0.4",
    "ionicons": "^5.0.1",
    "jquery": "^3.4.1",
    "jsdom": "^16.3.0",
    "loadjs": "^4.2.0",
    "location": "^0.0.1",
    "materialize-css": "^1.0.0",
    "moment": "^2.24.0",
    "prop-types": "^15.7.2",
    "react": "^16.11.0",
    "react-dnd": "^10.0.2",
    "react-dnd-html5-backend": "^10.0.2",
    "react-dom": "^16.11.0",
    "react_ujs": "^2.6.0",
    "shave": "^2.5.9",
    "twilio-video": "^2.0.1"
  },
  "devDependencies": {
    "babel-jest": "^24.9.0",
    "enzyme": "^3.10.0",
    "enzyme-adapter-react-16": "^1.15.1",
    "jest": "^24.9.0",
    "jest-enzyme": "^7.1.2",
    "regenerator-runtime": "^0.13.3",
    "webpack-dev-server": "^3.9.0",
    "workbox-webpack-plugin": "^4.3.1"
  },
  "scripts": {
    "test": "jest",
    "test-watch": "jest --watch"
  },
  "jest": {
    "roots": [
      "spec/javascript"
    ],
    "testMatch": [
      "**/spec/javascript/**?(*.)+(spec|test).[jt]s?(x)"
    ],
    "setupFiles": [
      "<rootDir>/spec/javascript/setupTest.js"
    ]
  }
}

Versions: webpacker 4.2.2 ruby 2.5.1 Rails 5.2.3

rossta commented 4 years ago

Do you have stylesheet_pack_tag in your view?

https://github.com/rails/webpacker/blob/master/docs/css.md#link-styles-from-your-rails-views

randall-coding commented 4 years ago

Thanks for the reply.

I did a find_all in my project folder and couldn't find 'stylesheet_pack_tag'. I have <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> instead, in my layout application.html.erb

rossta commented 4 years ago

That’s it then. By default, CSS gets extracted to a separate stylesheet “pack” file in production. You need to render it in your view.

randall-coding commented 4 years ago

Ok. I had assumed it was just talking about files referenced with an @import statement in application.scss.

Will give it a shot then.

randall-coding commented 4 years ago

That worked thanks. I added this line <%= stylesheet_pack_tag 'application' %>

But here is what is kind of bugging me. It seems that the declaration made in the react js file itself is superfluous. I removed the import ./Messenger.css;line and the css still compiles into the pack.

Therefore I wonder what is the point of the instructions here entitled "Import CSS from JS file" https://github.com/rails/webpacker/blob/master/docs/css.md#importing-css-from-js

It also seems like being able to load the css on demand per component is useful. It could reduce conflicts in the css code.

radiantshaw commented 4 years ago

@Randall-Coding I came across the same scenario where the import statement in React components seems to not do anything. It's all working correctly if I just do stylesheet_pack_tag 'application'. Did you find out how to make it work like create-react-app where we can import the CSS in individual components?

I know importing the CSS files individually does not offer much in Rails since everything is bundled in one application.css file. So now I'm starting to think why create-react-app does it that way, since it also bundles everything in one package. Maybe it's used while lazy loading the components? Maybe it lazy loads the CSS as well?

randall-coding commented 4 years ago

@radiantshaw

 Did you find out how to make it work like create-react-app where we can import the CSS in individual components?

I did not find a way to make it work as I had intended. It is bundling everything into one application.css. Maybe someone else knows how to make those import statements work on production.

winstonferguson commented 3 years ago

As I couldn't find much else online outside of this thread thought I'd comment.

I had the same issue and using import("path/file.css") not import "path/file.css" in my react components worked as intended. The import "path" method statically imports the exports of another module while the import("path") method dynamically loads modules.

Webpacker is integrating Webpack into Rails so it creates packs for use in Rails views. As views are static, it makes sense that it uses a static method once, when compiling, to create packs. Webpacker will even automatically create the pack based on the jsx file name containing import "path/file.css". Unless you tell Rails to output the pack, that module's content isn't going to make it onto the page.

Using import("path/file.css") in the jsx file enables Webpack to load the module when requested.

That's why I think import("path/file.css") works and import "path/file.css" doesn't.

See Webpack Module Methods and note the warning about import() and older browsers.

BrancuAlexandru commented 2 years ago

@poshcock I'm already doing that. Doesn't work for me.