webpack-contrib / mini-css-extract-plugin

Lightweight CSS extraction plugin
MIT License
4.66k stars 389 forks source link

External assets' urls get prefixed with "webpack:///mini-css-extract-plugin/" #945

Closed yoannmoinet closed 6 months ago

yoannmoinet commented 2 years ago

Bug report

Once built our CSS file tries to load external assets from webpack:///mini-css-extract-plugin/<actual url>.

It happens to fonts that loads with a relative path. But not when the font loads from an absolute path (eg. Google Fonts)

Actual Behavior

External assets' urls, when not absolute, are prefixed with webpack:///mini-css-extract-plugin/.

Expected Behavior

Once exported, the CSS should not have the prefix webpack:///mini-css-extract-plugin/ in the external assets' urls and load the asset as it's configured.

How Do We Reproduce?

Here's our mini-css-extract-plugin config:

new MiniCssExtractPlugin({
    filename: [...],
    chunkFilename: [...],
    attributes: {
        media: 'all'
    },
    ignoreOrder: true
}),

And our loader's configuration:

{
    test: /\.(less|css)$/,
    use: [
        MiniCssExtractPlugin.loader,
        {
            loader: 'css-loader',
            options: {
                sourceMap: true,
                import: false
            }
        },
        {
            loader: 'less-loader',
            options: {
                sourceMap: true,
                lessOptions: {
                    relativeUrls: true
                }
            }
        }
    ]
}

Please paste the results of npx webpack-cli info here, and mention other relevant information

  System:
    OS: macOS 12.3.1
    CPU: (8) x64 Intel(R) Core(TM) i7-1068NG7 CPU @ 2.30GHz
    Memory: 331.20 MB / 32.00 GB
  Binaries:
    Node: 16.3.0 - ~/.volta/tools/image/node/16.3.0/bin/node
    Yarn: 3.2.0 - ~/.volta/tools/image/yarn/1.22.18/bin/yarn
    npm: 7.15.1 - ~/.volta/tools/image/node/16.3.0/bin/npm
  Browsers:
    Brave Browser: 101.1.38.109
    Chrome: 101.0.4951.64
    Firefox: 98.0.2
    Safari: 15.4
  Monorepos:
    Yarn Workspaces: 3.2.0

I've managed to "fix" the problem by using experimentalUseImportModule: false in the plugin's configuration.

I'm coming from https://github.com/webpack-contrib/mini-css-extract-plugin/issues/936 as it apparently didn't follow the template, I'm trying to create a correct issue here.

Example of a CSS where you can see both absolute and relative urls ```css @import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap'); @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Regular-webfont-f2ca9b9f576ab78110a5fdd2477950a4.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Regular-webfont-d0c801fcdde512010a9541ee88fad273.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Regular-webfont-942475f652bbbabd2d3cce5085020560.ttf) format('truetype'); } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Bold-webfont-6cd614a680bf9ad4d3c4dbc489cce52b.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Bold-webfont-89f2d03c0fd6881f91f062e3f54574d9.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Bold-webfont-feda1ac068b693c673265c31254fd376.ttf) format('truetype'); font-weight: bold; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBold-webfont-1aef7e2308de2eea6d9c04a0d9e42e59.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBold-webfont-32cc3d694fd0e73903b137e3707b80ca.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBold-webfont-e2c2bc20049bf8fc82a94927ae111294.ttf) format('truetype'); font-weight: 600; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Light-webfont-d923425660284e0d066a47a395d65595.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Light-webfont-a7ca6811908abe1695b35f82fa669573.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Light-webfont-e8303047513bc70e9fc6cb1e6c222785.ttf) format('truetype'); font-weight: 300; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Italic-webfont-5f46ce03d422f513e34a43cf344eb831.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Italic-webfont-8e53d983f215727af85995f8e080e4c6.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Italic-webfont-102f599d6b71b64d0ec7e19e08e92de8.ttf) format('truetype'); font-style: italic; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-BoldItalic-webfont-317b0ce976190591633c19234fe54190.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-BoldItalic-webfont-f713c40de27886b77b0a997534dccd9f.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-BoldItalic-webfont-087173dea1d4956e0c5b8a31492f3ad9.ttf) format('truetype'); font-weight: bold; font-style: italic; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBoldItalic-webfont-69e481b884bfe32236810da3289300de.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBoldItalic-webfont-2e93ba504a6bd00b870540b2a4feca25.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBoldItalic-webfont-3fda80b8bdf65bfaeee8497d0041320b.ttf) format('truetype'); font-weight: 600; font-style: italic; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-LightItalic-webfont-1ea8d3a02ec18c95b9463d5c1cb2928c.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-LightItalic-webfont-beab8ff982cccf6d2f6a7c3414149754.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-LightItalic-webfont-b1e83b2f2bb6869f046f46a2a60d4a11.ttf) format('truetype'); font-weight: 300; font-style: italic; } ```
vankop commented 2 years ago

could you provide example css file?

yoannmoinet commented 2 years ago

I can give a snippet of one of them.

Click to expand ```css @import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap'); @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Regular-webfont-f2ca9b9f576ab78110a5fdd2477950a4.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Regular-webfont-d0c801fcdde512010a9541ee88fad273.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Regular-webfont-942475f652bbbabd2d3cce5085020560.ttf) format('truetype'); } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Bold-webfont-6cd614a680bf9ad4d3c4dbc489cce52b.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Bold-webfont-89f2d03c0fd6881f91f062e3f54574d9.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Bold-webfont-feda1ac068b693c673265c31254fd376.ttf) format('truetype'); font-weight: bold; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBold-webfont-1aef7e2308de2eea6d9c04a0d9e42e59.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBold-webfont-32cc3d694fd0e73903b137e3707b80ca.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBold-webfont-e2c2bc20049bf8fc82a94927ae111294.ttf) format('truetype'); font-weight: 600; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Light-webfont-d923425660284e0d066a47a395d65595.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Light-webfont-a7ca6811908abe1695b35f82fa669573.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Light-webfont-e8303047513bc70e9fc6cb1e6c222785.ttf) format('truetype'); font-weight: 300; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Italic-webfont-5f46ce03d422f513e34a43cf344eb831.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Italic-webfont-8e53d983f215727af85995f8e080e4c6.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-Italic-webfont-102f599d6b71b64d0ec7e19e08e92de8.ttf) format('truetype'); font-style: italic; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-BoldItalic-webfont-317b0ce976190591633c19234fe54190.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-BoldItalic-webfont-f713c40de27886b77b0a997534dccd9f.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-BoldItalic-webfont-087173dea1d4956e0c5b8a31492f3ad9.ttf) format('truetype'); font-weight: bold; font-style: italic; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBoldItalic-webfont-69e481b884bfe32236810da3289300de.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBoldItalic-webfont-2e93ba504a6bd00b870540b2a4feca25.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-SemiBoldItalic-webfont-3fda80b8bdf65bfaeee8497d0041320b.ttf) format('truetype'); font-weight: 600; font-style: italic; } @font-face { font-family: 'NotoSans'; font-style: normal; font-weight: normal; src: url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-LightItalic-webfont-1ea8d3a02ec18c95b9463d5c1cb2928c.woff2) format('woff2'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-LightItalic-webfont-beab8ff982cccf6d2f6a7c3414149754.woff) format('woff'), url(webpack:///mini-css-extract-plugin//static/v/33.dev0/js/NotoSans-LightItalic-webfont-b1e83b2f2bb6869f046f46a2a60d4a11.ttf) format('truetype'); font-weight: 300; font-style: italic; } ```

Adding it to the main issue's description.

vankop commented 2 years ago

@yoannmoinet I mean original one, that you are using in your application and can you provide full list of module.rules

yoannmoinet commented 2 years ago

full list of module.rules

It's not shareable, it's 300+ line of codes, relies on outside functions, and it's private. So I've shared the relevant part, the only rules applied to .less files.

We have two others that may be related to assets:

{
    resourceQuery: /raw/,
    type: 'asset/source'
},
{
    test: /\.(png|jpg|gif|woff2|woff|eot|ttf|mp4|webm|cur|)$/,
    use: {
        loader: 'file-loader',
        options: {
            name: `${destination.chunk}/[name]-[hash].[ext]`
        }
    }
},

With destination.chunk = 'c'

I mean original one

Here's a snippet of the less code that generates the faulty CSS.

// Parametric mixin to generate the static urls for web fonts
.webfont(@family, @file, @name) {
    @f: %('~[...local-assets-path...]/%s', @file);
    @woff2: %('%s.woff2', @f);
    @woff: %('%s.woff', @f);
    @ttf: %('%s.ttf', @f);

    font-family: @family;
    font-style: normal;
    font-weight: normal;
    src: url(@woff2) format('woff2'), url(@woff) format('woff'),
        url(@ttf) format('truetype');
}

@font-face {
    .webfont('NotoSans', 'NotoSans-Regular-webfont', 'NotoSansRegular');
}

@import (css)
    url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap');
alexander-akait commented 2 years ago

Please add resourceQuery: { not: [/raw/] }, for file-loader, described here https://webpack.js.org/guides/asset-modules/#replacing-inline-loader-syntax

alexander-akait commented 2 years ago

You just apply two loader for the same file

yoannmoinet commented 2 years ago

Please add resourceQuery: { not: [/raw/] }, for file-loader

Thanks for the tip. Just to note that it doesn't fix the issue though.

alexander-akait commented 2 years ago

@yoannmoinet, why you use file-loader? It is deprecated and should be removed, anyway you miss type: 'javascript/auto', you can found all cases https://webpack.js.org/guides/asset-modules/.

As alternative solutions you can set esModule: false for css-loader and mini-css-extrat-plugin, so we will generate require for assets

vankop commented 2 years ago
{
    test: /\.(woff2|woff|ttf)$/,
    type: "asset"
},
{
    resourceQuery: /raw/,
    type: 'asset/source'
},

you can just use type: asset instead of file-loader also you can control naming by assetFilename https://webpack.js.org/guides/asset-modules/#custom-output-filename


but I'm not sure that this will resolve problem..

lxndr commented 2 years ago

bumped into the same issue while importing css in nextjs app.

vankop commented 2 years ago

@lxndr could you create reproducible repo?

PeterBerryman commented 2 years ago

I had this issue with nextjs importing minified css from a node_module using webpack 5. I'm not at all clear yet which of nextjs, mini-css-extract-plugin or myself were to blame. I'll try to put together a minimal example.

However, since this is a top result on google I can say at this point that adding

config.module.generator.asset.publicPath = "/_next/";

to next.config.js to force the public path made the problem go away!

nslee333 commented 1 year ago

@vankop

https://github.com/BendJS/simple-website/tree/tailwind

I have one right here - using Next.js with Tailwind on the project, ran into background image not displaying after deploying to Netlify only after starting to use Tailwind.

Traced the background to not showing up to my styles.globals.css file in /src/styles/styles.globals.css.

I ran the build locally and inspected and found that the URL was prefixed with webpack:///mini-css-extract-plugin/....

.next/static/css/026b89374cf46772.css <- I'm not sure if this is the exact file name that you will get when you build locally but this is what it was listed in for me.

background:url(webpack:///mini-css-extract-plugin/_next/static/media/hero_image.6ce705e5.jpg) 
nslee333 commented 1 year ago

config.module.generator.asset.publicPath = "/_next/";

to next.config.js to force the public path made the problem go away!

@PeterBerryman Can you elaborate on this workaround please? Not having much luck on making it work.

Edit: I figured it out, here's my full next.config.js file with the workaround for anyone who is running into this issue with Next.js

next.config.js

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  compiler: {
    styledComponents: true,
  },
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "cdn.sanity.io",
      },
    ],
  },
  webpack: (
    config,
    { buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }
    ) => {
      plugins: [
        config.module.generator.asset.publicPath = "/_next/",
        new MiniCssExtractPlugin({
          experimentalUseImportModule: false
        }),
      ]
    return config
  },
};
alexander-akait commented 1 year ago

experimentalUseImportModule: false is not good solution. Can you reproduce it without next.js? Maybe they rewrite some things in CSS

alexander-akait commented 1 year ago

@nslee333 I can't use your repo because of:

info  - Linting and checking validity of types  
info  - Compiled successfully
info  - Collecting page data .Error: Configuration must contain `projectId`
    at initConfig (/home/akait/IdeaProjects/simple-website/node_modules/@sanity/client/dist/index.cjs:1037:11)
    at _SanityClient.config (/home/akait/IdeaProjects/simple-website/node_modules/@sanity/client/dist/index.cjs:1648:40)
    at new _SanityClient (/home/akait/IdeaProjects/simple-website/node_modules/@sanity/client/dist/index.cjs:1622:10)
    at createClient (/home/akait/IdeaProjects/simple-website/node_modules/@sanity/client/dist/index.cjs:1763:32)
    at /home/akait/IdeaProjects/simple-website/.next/server/chunks/580.js:842:73
alexander-akait commented 1 year ago

So, if somebody provides me reproducible example I will investigate and try to find there is the problem - our bug or nextjs, thank you

alexander-akait commented 6 months ago

Closing due to inactivity. Please test with latest version and feel free to reopen if still regressions. Thanks!

nazmulsujon commented 5 months ago

Please add resourceQuery: { not: [/raw/] }, for file-loader

Thanks for the tip. Just to note that it doesn't fix the issue though.

Next.js can serve static files, like images, under a folder called public in the root directory. Files inside public can then be referenced by your code starting from the base URL (/). For example, the file public/avatars/me.png can be viewed by visiting the /avatars/me.png path.

nazmulsujon commented 5 months ago

Next.js can serve static files, like images, under a folder called public in the root directory. Files inside public can then be referenced by your code starting from the base URL (/).

For example, the file public/avatars/me.png can be viewed by visiting the /avatars/me.png path.

Zekfad commented 1 month ago

Same issue with webpack:///mini-css-extract-plugin prefix, same fix with experimentalUseImportModule: false. Also worth of noting, that specifying publicPath in asset generator options changes prefix to webpack:// + specified public path. We use pure webpack without any framework on top of it.

alexander-akait commented 1 month ago

@Zekfad can you create repreducible test repo?

Zekfad commented 1 month ago

@alexander-akait I'll try to extract minimum reproducible config in a following week.

alexander-akait commented 1 month ago

@Zekfad thank you, feel free to ping me