How to (successfully) bundle css for dynamic multi-page app using Webpack 5
Asked Answered
C

1

0

I am trying to use Webpack 5 to bundle assets for a dynamic multi-page Django application. Using WebpackManifestPlugin and django-manifest-loader. I have this working fine for JavaScript, but I've tried every tip I can find and have not been able to make it work for css.

I have created a css file to use as an entry point and (for proof of concept) imported 1 of the application's css files into that. The output file that is produced from that is effectively empty. If I add any rules directly to the entry .css file, then those rules show up in the output file, but the @import … is gone and the rules from the imported file are not present.

Incidentally, if I purposefully mis-name the file in the import, then bundling fails, so I think the imported css is being correctly recognized and processed, then omitted. Based on some of the reading I have done, I added sideEffects: true (see django/webpack.config.js contents below) but that did not change the results.

Any advice? I've been tearing my hair out for almost 2 days on this.

django/ui/src/index.css

@import 'css/components/navigation/notifications.css';

Resulting django/dist/main.512f6e37f2c08258132d.css

/*!******************************************************************************************************!*\     
  !*** css ./node_modules/css-loader/dist/cjs.js!./ui/src/css/components/navigation/notifications.css ***!       
  \******************************************************************************************************/       
                                                                                                                 
/*!***********************************************************************************************************!*\
  !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./ui/src/index.css ***!  
  \***********************************************************************************************************/  

Here's what I have in my django/webpack.config.js file:

/*global __dirname, module, require*/                                   
                                                                        
const path = require('path');                                           
const {CleanWebpackPlugin} = require('clean-webpack-plugin');           
const {WebpackManifestPlugin} = require('webpack-manifest-plugin');     
const MiniCssExtractPlugin = require("mini-css-extract-plugin");        
                                                                        
module.exports = {                                                      
  entry: {                                                              
      main: ['./ui/src/index.js', './ui/src/index.css'],                
  },                                                                    
  devtool: 'inline-source-map',                                         
  plugins: [                                                            
      // Remove outdated assets from the output dir                     
      new CleanWebpackPlugin(),                                         
      // Generate the required manifest.json file                       
      new WebpackManifestPlugin(),                                      
      new MiniCssExtractPlugin({                                        
          filename: '[name].[contenthash].css',                         
      }),                                                               
  ],                                                                    
  module: {                                        
      rules: [                                     
          {                                        
              test: /\.(sa|sc|c)ss$/,              
              use: [                               
                  MiniCssExtractPlugin.loader,     
                  "css-loader",                    
                  "sass-loader",                   
              ],                                   
              sideEffects: true,                   
          },                                       
          {                                        
              test: require.resolve('vue'),        
              loader: 'expose-loader',             
              options: {                           
                  exposes: ['Vue'],                
              },                                   
          },                                       
      ],                                           
  },                                               
  output: {                                                                                   
      // Rename files from example.js to example.8f77someHash8adfa.js                         
      filename: '[name].[contenthash].js',                                                    
      path: path.resolve(__dirname, 'dist'),                                                  
      // https://webpack.js.org/migrate/5/                                                    
      // > * 404 errors pointing to URLs containing auto                                      
      // >    - Not all ecosystem tooling is ready for the new default                        
      // >      automatic publicPath via output.publicPath: "auto"                            
      // >       - Use a static output.publicPath: "" instead.                                
      publicPath: '',                                                                         
  },                                                                                          
  resolve: {                                                                                  
    alias: {                                                                                  
        // If using the runtime only build                                                    
        vue$: 'vue/dist/vue.runtime.esm.js', // 'vue/dist/vue.runtime.common.js' for webpack 1
        // Or if using full build of Vue (runtime + compiler)                                 
        // vue$: 'vue/dist/vue.esm.js'      // 'vue/dist/vue.common.js' for webpack 1         
    },                                                                                        
  },                                                                                          
};                                                                                            

In case it's helpful, here's what is in my django/package.json:

{                                                  
  "name": "hub-ui",                                
  "version": "0.0.1",                              
  "description": "",                               
  "main": "index.js",                              
  "scripts": {                                     
    "start": "webpack --watch --mode=development", 
    "build": "webpack --mode=production",          
    "dev": "webpack --mode=development"            
  },                                               
  "keywords": [],                                  
  "author": "Cliosoft",                            
  "devDependencies": {                             
    "clean-webpack-plugin": "^3.0.0",              
    "css-loader": "^6.3.0",                        
    "eslint": "^7.32.0",                           
    "eslint-plugin-vue": "^7.18.0",                
    "expose-loader": "^3.0.0",                     
    "mini-css-extract-plugin": "^2.3.0",           
    "node-sass": "^6.0.1",                         
    "sass-loader": "^12.1.0",                      
    "style-loader": "^3.2.1",                      
    "webpack": "^5.0.0",                           
    "webpack-cli": "^4.8.0",                       
    "webpack-manifest-plugin": "^4.0.2"            
  },                                               
  "dependencies": {            
    "bootstrap": "^5.1.1",     
    "bootstrap-vue": "^2.21.2",
    "vue": "^2.6.14"           
  },                           
  "engines": {                 
    "node": "~16.9",           
    "npm": "~7.23"             
  }                            
}                              
Cosher answered 24/9, 2021 at 8:37 Comment(1)
I also just tried "sideEffects": "./ui/src/css/**/*" in my package.json. That didn't fix it. Tried changing that to "sideEffects": true and that still had no effect on the problem.Cosher
C
0

This turned out to be a "did you turn it on?" kind of problem.

The css file I was using as the test case was supposedly a copy of a css file from its previous location, but it was actually an empty file of the same name. Doh!

Once I actually copied the styles into the .css file, everything started to work correctly.

Hopefully, this will be of some help to someone in the future. If you spend many days trying to figure out what's wrong with your package.json, webpack.config.js, etc. and can't find anything wrong with them, then maybe the problem is somewhere else like not having the content in your source files that you think you have.

Cosher answered 27/9, 2021 at 21:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.