0

I was able to produce separate CSS and Js as mentioned at: Can I use webpack to generate CSS and JS separately?

The working baseline code below produces files named:

dist/index.js
dist/main.css
dist/main.js
dist/notmain.css
dist/notmain.js

Note that undesired main.js and notmain.js dummy files which no ones knows how to nicely fix, but it doesn't matter to me in this case.

My question is, how can I get Webpack to instead generate:

dist/index.css
dist/index.js
dist/notmain.css

i.e., rename main.css to index.css?

?

Naively, what I wanted would be to just modify the working baseline to:

  entry: {
    index: ['./index.js'],
    index: ['./index.scss'],
  },

but then that wouldn't make any sense, since the entry dict now has two index keys, and the second one would erase the first.

Also, if I had just a single CSS output, I could just hardcode:

    new MiniCssExtractPlugin({
      filename: 'index.css',
    }),

but since I have multiple ones, that won't cut it, I need that [name] placeholder to work somehow.

I've seen at https://webpack.js.org/configuration/entry-context/#output-filename that it documents that something like:

    main: {
      import: './main.scss',
      filename: 'index.css',
    },

could work, but if I try that it fails with:

ERROR in index.css
index.css from Css Minimizer
/home/ciro/bak/git/cirosantilli.github.io/webpack/tmp/index.css:1:10: Unknown word [index.css:1,10]

A similar question about this error message can be seen at: webpack fails "module build failed: unknown word" with webpack.config.js file What happens is that for some reason dist/index.css contains a JavaScript file, and the then CSS minifier fails to parse it. An analogous change for index.js did work for JavaScript though, it's something specific to this CSS setup.

Working baseline code

index.html

<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>Sass import</title>
<link rel="stylesheet" href="dist/main.css">
<link rel="stylesheet" href="dist/notmain.css">
</head>
<body>
<p>Hello</p>
<script src="dist/index.js"></script>
</body>
</html>

index.js

document.getElementsByTagName('body')[0].innerHTML += '<p>js works</p>'

main.scss

body {
  background-color: red;
}

notmain.scss

body {
  color: blue;
}

webpack.config.js

const path = require('path');

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const nodeModulesPath = path.resolve(__dirname, 'node_modules');

module.exports = {
  entry: {
    index: ['./index.js'],
    main: ['./main.scss'],
    notmain: ['./notmain.scss'],
  },
  mode: 'none',
  module: {
    rules: [
      {
        test: /\.(scss|css)$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'sass-loader',
        ],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
    }),
  ],
  optimization: {
    minimizer: [
      new CssMinimizerPlugin(),
    ],
    minimize: true,
  },
  output: {
    filename: '[name].js',
  },
};

package.json

{
  "name": "webpack-cheat",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "webpack",
    "sass": "rm -f dist/main.css && sass -I node_modules main.scss dist/main.css"
  },
  "author": "Ciro Santilli",
  "license": "MIT",
  "devDependencies": {
    "css-loader": "5.2.4",
    "css-minimizer-webpack-plugin": "3.0.2",
    "mini-css-extract-plugin": "2.1.0",
    "normalize.css": "8.0.1",
    "sass": "1.32.11",
    "sass-loader": "11.0.1",
    "style-loader": "2.0.0",
    "webpack": "5.36.1",
    "webpack-cli": "4.6.0",
    "webpack-dev-server": "3.11.2"
  }
}

Compile and run:

npm install
npm run build
xdg-open index.html

Also asking at: https://github.com/webpack/webpack/discussions/15163

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985

2 Answers2

0

The amazing Webpack developer Alexander Akait just replied to me with a working workaround:

  plugins: [
    new MiniCssExtractPlugin({
      filename: (pathData) => {
        if (pathData.chunk.name === "main") {
          return 'index.css'
        }

        return '[name].css'
      },
    }),
  ],

so we see that filename can take an arbitrary function and not just strings, and then we are able to fix things up with that greater flexibility.

He also mentions:

I see, yep, it is limitation, we are working on built-in CSS support (it will resolve the problem), currently please use:

so it appears that Webpack as historically been more focused on the "inject CSS with Js approach", but that this is now being generalized.

Thanks Alexander!

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
0

You want something similar to this, here are some excerpts from my own config, using webpack v5:

module.exports = {
 // other stuff omitted
 output: {
    // other stuff omitted
    filename: '[name].js',
    chunkFilename: '[name].js'
  },
  entry: {
    index: [
      './src/index.js'
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      ignoreOrder: true
    }),
  ]
} 

the [name] substituion can be used to map back to the name on disk.

see

for more information

random-forest-cat
  • 33,652
  • 11
  • 120
  • 99