Repository: webpack-contrib/mini-css-extract-plugin (js)

Issue:
outputOptions.pathInfo = true breaks sourcemaps
- Operating System:
- Node Version:
- NPM Version:
- webpack Version: 5.51.1
- mini-css-extract-plugin Version: 2.2.0

### Expected Behavior

Source map line numbers are correct, even with `outputOptions.pathinfo` is true

### Actual Behavior

https://github.com/webpack-contrib/mini-css-extract-plugin/pull/783 adds a 3 line comment block to the top of the output; so source map line numbers are all off by 3

### Code

### How Do We Reproduce?

With a sourcemapped setup, click on a css class link in browser dev tools, and notice that the link shows the wrong line in the source.


Pull request description:
fix: source map generation with pathinfo
<!--
  HOLY CRAP a Pull Request. We ❤️ those!

  If you remove or skip this template, you'll make the 🐼 sad and the mighty god
  of Github will appear and pile-drive the close button from a great height
  while making animal noises.

  Please place an x (no spaces!) in all [ ] that apply
-->

This PR contains a:

- [x] **bugfix**
- [ ] new **feature**
- [ ] **code refactor**
- [x] **test update** <!-- if bug or feature is checked, this should be too -->
- [ ] **typo fix**
- [ ] **metadata update**

### Motivation / Use-Case

fix #814 

### Breaking Changes

No

### Additional Info

Fix source map generation with pathinfo

Patch:
diff --git a/src/index.js b/src/index.js
index 2eac6f7..d114469 100644
--- a/src/index.js
+++ b/src/index.js
@@ -991,16 +991,22 @@ class MiniCssExtractPlugin {
       const readableIdentifier = module.readableIdentifier(requestShortener);
       const startsWithAtRuleImport = /^@import url/.test(content);
 
+      let header;
+
       if (compilation.outputOptions.pathinfo) {
         // From https://github.com/webpack/webpack/blob/29eff8a74ecc2f87517b627dee451c2af9ed3f3f/lib/ModuleInfoHeaderPlugin.js#L191-L194
         const reqStr = readableIdentifier.replace(/\*\//g, "*_/");
         const reqStrStar = "*".repeat(reqStr.length);
         const headerStr = `/*!****${reqStrStar}****!*\\\n  !*** ${reqStr} ***!\n  \\****${reqStrStar}****/\n`;
 
-        content = headerStr + content;
+        header = new RawSource(headerStr);
       }
 
       if (startsWithAtRuleImport) {
+        if (typeof header !== "undefined") {
+          externalsSource.add(header);
+        }
+
         // HACK for IE
         // http://stackoverflow.com/a/14676665/1458162
         if (module.media) {
@@ -1013,6 +1019,10 @@ class MiniCssExtractPlugin {
         externalsSource.add(content);
         externalsSource.add("\n");
       } else {
+        if (typeof header !== "undefined") {
+          source.add(header);
+        }
+
         if (module.media) {
           source.add(`@media ${module.media} {\n`);
         }


Test patch:
diff --git a/test/cases/pathinfo-devtool-source-map/expected/main.css b/test/cases/pathinfo-devtool-source-map/expected/main.css
new file mode 100644
index 0000000..cb08fe1
--- /dev/null
+++ b/test/cases/pathinfo-devtool-source-map/expected/main.css
@@ -0,0 +1,23 @@
+/*!********************************************************************!*\
+  !*** css ../../../node_modules/css-loader/dist/cjs.js!./style.css ***!
+  \********************************************************************/
+body {
+  background: red;
+}
+
+/*!********************************************************************!*\
+  !*** css ../../../node_modules/css-loader/dist/cjs.js!./other.css ***!
+  \********************************************************************/
+body {
+  background: blue;
+}
+
+/*!********************************************************************!*\
+  !*** css ../../../node_modules/css-loader/dist/cjs.js!./extra.css ***!
+  \********************************************************************/
+body {
+  background: yellow;
+}
+
+
+/*# sourceMappingURL=main.css.map*/
\ No newline at end of file
diff --git a/test/cases/pathinfo-devtool-source-map/expected/main.css.map b/test/cases/pathinfo-devtool-source-map/expected/main.css.map
new file mode 100644
index 0000000..fb0ac34
--- /dev/null
+++ b/test/cases/pathinfo-devtool-source-map/expected/main.css.map
@@ -0,0 +1,1 @@
+{"version":3,"file":"main.css","mappings":";;;AAAA;EACE,eAAe;AACjB;;;;;ACFA;EACE,gBAAgB;AAClB;;;;;ACFA;EACE,kBAAkB;AACpB","sources":["webpack:///./style.css","webpack:///./other.css","webpack:///./extra.css"],"sourcesContent":["body {\n  background: red;\n}\n","body {\n  background: blue;\n}\n","body {\n  background: yellow;\n}\n"],"names":[],"sourceRoot":""}
\ No newline at end of file
diff --git a/test/cases/pathinfo-devtool-source-map/extra.css b/test/cases/pathinfo-devtool-source-map/extra.css
new file mode 100644
index 0000000..19f9965
--- /dev/null
+++ b/test/cases/pathinfo-devtool-source-map/extra.css
@@ -0,0 +1,3 @@
+body {
+  background: yellow;
+}
diff --git a/test/cases/pathinfo-devtool-source-map/index.js b/test/cases/pathinfo-devtool-source-map/index.js
new file mode 100644
index 0000000..938a4b6
--- /dev/null
+++ b/test/cases/pathinfo-devtool-source-map/index.js
@@ -0,0 +1,3 @@
+import "./style.css";
+import "./other.css";
+import "./extra.css";
diff --git a/test/cases/pathinfo-devtool-source-map/other.css b/test/cases/pathinfo-devtool-source-map/other.css
new file mode 100644
index 0000000..ae844dc
--- /dev/null
+++ b/test/cases/pathinfo-devtool-source-map/other.css
@@ -0,0 +1,3 @@
+body {
+  background: blue;
+}
diff --git a/test/cases/pathinfo-devtool-source-map/style.css b/test/cases/pathinfo-devtool-source-map/style.css
new file mode 100644
index 0000000..67ce83e
--- /dev/null
+++ b/test/cases/pathinfo-devtool-source-map/style.css
@@ -0,0 +1,3 @@
+body {
+  background: red;
+}
diff --git a/test/cases/pathinfo-devtool-source-map/webpack.config.js b/test/cases/pathinfo-devtool-source-map/webpack.config.js
new file mode 100644
index 0000000..97f53b6
--- /dev/null
+++ b/test/cases/pathinfo-devtool-source-map/webpack.config.js
@@ -0,0 +1,22 @@
+import Self from "../../../src";
+
+module.exports = {
+  entry: "./index.js",
+  devtool: "source-map",
+  output: {
+    pathinfo: true,
+  },
+  module: {
+    rules: [
+      {
+        test: /\.css$/,
+        use: [Self.loader, "css-loader"],
+      },
+    ],
+  },
+  plugins: [
+    new Self({
+      filename: "[name].css",
+    }),
+  ],
+};