mini-css-extract-plugin icon indicating copy to clipboard operation
mini-css-extract-plugin copied to clipboard

module.generator.asset.publicPath='/' throw error

Open ckken opened this issue 2 years ago • 31 comments

Bug report

{
    module: {
      // mini-css-extract-plugin HookWebpackError: Invalid URL: /assets/logo.635a60f2.jpg
      generator: {
        asset: {
          publicPath: '/',
        },
      },
    },
   output:{
        publicPath:'auto'
   }
}

Actual Behavior

image

Expected Behavior

image

How Do We Reproduce?

{
    module: {
      generator: {
        asset: {
          publicPath: '/',
        },
      },
    },
   output:{
        publicPath:'auto'
   }
}
<!-- A great way to do this is to provide your configuration via a GitHub repository -->
<!-- The most helpful is a minimal reproduction with instructions on how to reproduce -->
<!-- Repositories with too many files or large `webpack.config.js` files are not suitable -->
<!-- Please only add small code snippets directly into this issue -->
<!-- https://gist.github.com is a good place for longer code snippets -->
<!-- If your issue is caused by a plugin or loader, please create an issue on the loader/plugin repository instead -->

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

ckken avatar Nov 18 '21 08:11 ckken

Please fill out all fields

alexander-akait avatar Nov 18 '21 10:11 alexander-akait

https://github.com/ckken/webpack-boilerplate thanks reply

ckken avatar Nov 20 '21 11:11 ckken

Remove:

 generator: {
      'asset/resource': {
        publicPath: '/',
      },
    },

Yes says webpack to have auto public path and override it for CSS, it is not good

alexander-akait avatar Nov 25 '21 19:11 alexander-akait

It works without specifying the publicPath. But I still don't understand why the publicPath should not be specified specifically. (because it works with [email protected].) Maybe the error message should be more clear, or maybe the doc should mention this situation?

Clarkkkk avatar Dec 01 '21 17:12 Clarkkkk

It is limitation due new URL(...) syntax, because we execute it on Node.js, you see this problem, due invalid public path calculated in new URL(...), anyway in theory we can improve it, can you provide small example? maybe we have bug

alexander-akait avatar Dec 01 '21 17:12 alexander-akait

Maybe my example from here helps, as it seems the same issue: https://github.com/webpack/webpack/discussions/14920

The repo: https://github.com/ldrick/webpack_asset_resource

ldrick avatar Dec 09 '21 17:12 ldrick

@ckken You should not use generator in your case, just set

{
  loader: MiniCssExtractPlugin.loader,
  options: {
    publicPath: '/'
  }
},

Why? Because you can't combine auto and /, webpack can't understand how to calculate valid URL

alexander-akait avatar Dec 15 '21 15:12 alexander-akait

@ldrick You example is more complex, you try to create relative URL inside auto context, I am afraid it is impossible, when you have auto, webpack calculates URL from output.path and convert them to relative based on output.path, that is why you have

../../../files/themes/mytheme/fontawesome/fa-regular-400.svg#fontawesome

But in context of all styles, you can have other url() and these files can be in other directories. Shorty - you need different public paths for different url(), hard... anyway I think you can achieve it using some hacky things - move fontawesome in separate file and setup MiniCssExtractPlugin.loader (and other loaders) only for fontawesome file like you do it for fonts and use the publicPath option of MiniCssExtractPlugin.loader. I do not test it, but in theory it should works.

alexander-akait avatar Dec 15 '21 16:12 alexander-akait

I have the same problem. How to solve it

ccy303 avatar Dec 23 '21 13:12 ccy303

I have to chime in to say the loss of support for publicPath on the extract plugin causes an incompatibility when importing the same file from both CSS and JavaScript. For example, for a file hosted at /fonts/font.woff, let's say you import font.woff from inside a CSS file, and then inside a JavaScript file. The lost publicPath support means it's impossible for the JavaScript output and the CSS output to resolve the same public path correctly. Trying to use different asset/resource configurations (one for CSS and one for JavaScript issuers) also doesn't work as webpack won't duplicate the imported font file.

With publicPath set to "/fonts/"

import font from "./font.woff";
// font = /fonts/font.woff ✅
@font-face {
  font-family: font;
  src: url("./font.woff") format("woff"); /*** 💥 throws Invalid URL ***/
}

When publicPath not set

import font from "./font.woff";
// font = /font.woff ❌
@font-face {
  font-family: font;
  src: url("./font.woff") format("woff");  /*** ❌ resolves to "/font.woff" ***/
}

When publicPath not set on generator, but set to"/fonts/" on the loader plugin options itself

import font from "./font.woff";
// font = /font.woff ❌
@font-face {
  font-family: font;
  src: url("./font.woff") format("woff"); /*** ✅ resolves to "/fonts/font.woff" ***/
}

samkelleher avatar Jan 05 '22 14:01 samkelleher

Can you provide full minimum configuration, we have some edge cases... want to investigate

alexander-akait avatar Jan 06 '22 12:01 alexander-akait

@alexander-akait To reproduce this issue, the key is you need to set the type to asset/resource and set publicPath in generator. Like this:

{
    module: {
        rules: [
            {
                test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
                type: 'asset/resource',
                generator: {
                    publicPath: '//cdn.example.com/assets/',
                }
            },
        ],
    },
}

Here is a reproducible project: webpack-mini-css-public-path-issue.zip

Just run yarn install and yarn build you will see the error:

ERROR in ./src/index.css
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
HookWebpackError: Invalid URL: //cdn.example.com/assets/1fcab817090e78435061.svg
....
-- inner error --
TypeError [ERR_INVALID_URL]: Invalid URL: //cdn.example.com/assets/1fcab817090e78435061.svg
...

scarletsky avatar Jan 14 '22 04:01 scarletsky

@scarletsky Yep, because it is wrong URL, please use https://cdn.example.com/assets/, try to use it in new URL("//cdn.example.com/assets/"), we use new URL(...) for creating asset dependencies, another solution is set public path on loader level, i.e.

{
  loader: MiniCssExtractPlugin.loader,
  options: {
    publicPath: '//cdn.example.com/assets/',
  },
},

alexander-akait avatar Jan 14 '22 11:01 alexander-akait

@alexander-akait Thanks for your reply. It seems the publicPath on loader level can work with background-image: url(xxx), but it does not work with the path import from js.

Just do these changes:

// src/index.js
// import './index.css';
import url from './assets/webpack.svg';

console.log("Hello World!", url);
// webpack.config.js
rules: [
  {
    test: /\.css$/i,
    use: [
      {
        loader: MiniCssExtractPlugin.loader,
        options: {
          publicPath: '//cdn.example.com/assets/',
        },
      },
      'css-loader'
    ],
  },
  {
    test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
    type: 'asset/resource',
  },
]

The publicPath is not work:

cat dist/main.js

(()=>{"use strict";var r,t={347:(r,t,e)=>{r.exports=e.p+"1fcab817090e78435061.svg"}},e={};function o(r){var i=e[r];if(void 0!==i)return i.exports;var n=e[r]={exports:{}};return t[r](n,n.exports,o),n.exports}o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(r){if("object"==typeof window)return window}}(),(()=>{var r;o.g.importScripts&&(r=o.g.location+"");var t=o.g.document;if(!r&&t&&(t.currentScript&&(r=t.currentScript.src),!r)){var e=t.getElementsByTagName("script");e.length&&(r=e[e.length-1].src)}if(!r)throw new Error("Automatic publicPath is not supported in this browser");r=r.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),o.p=r})(),r=o(347),console.log("Hello World!",r)})();%

If we set publicPath in both MiniCssExtractPlugin.Loader options and generator, it will still throw the same Error.

scarletsky avatar Jan 14 '22 14:01 scarletsky

publicPath on plugin level only for CSS, not for JS, but yes, we need to think how to solve it, that is why it is not closed

alexander-akait avatar Jan 14 '22 14:01 alexander-akait

Any updates? Still a blocking problem right now for us.

IPRIT avatar Feb 20 '22 19:02 IPRIT

Same for us, it worked in previous versions like a charm and now our Framework can't use publicPath anymore because of that limitation.

How is it meant to use different runtime publicPaths for different resources then?

BR, Kev

KevinGruber avatar Mar 01 '22 08:03 KevinGruber

There is solution https://github.com/webpack-contrib/mini-css-extract-plugin/pull/915

alexander-akait avatar Mar 01 '22 12:03 alexander-akait

Somebody can try https://github.com/webpack-contrib/mini-css-extract-plugin/releases/tag/v2.6.0?

alexander-akait avatar Mar 03 '22 20:03 alexander-akait

It still does not work for me with v2.6.0.

s3curitybug avatar Mar 04 '22 10:03 s3curitybug

@s3curitybug Can you provide reproducible example?

alexander-akait avatar Mar 04 '22 10:03 alexander-akait

@s3curitybug you need to upgrade webpack to 5.70 also.

vankop avatar Mar 04 '22 10:03 vankop

I reduced my project to the minimum possible: https://github.com/s3curitybug/test-mini-css-extract-plugin

This works with v2.3.0, but does not with newer ones (even with webpack 5.70).

s3curitybug avatar Mar 04 '22 11:03 s3curitybug

@alexander-akait I think this related to css-loader

var ___CSS_LOADER_URL_IMPORT_0___ = new URL(
/* asset import */ __webpack_require__("asset/resource|/Users/ivankopeykin/Repositories/test-mini-css-extract-plugin/src/main/front/style/fonts/S6u8w4BMUTPHjxsAUi-qJCY.woff2")
, __webpack_require__.b);

vankop avatar Mar 04 '22 11:03 vankop

@vankop But we don't do nothing special in css-loader, just convert url() to new URL(...)

alexander-akait avatar Mar 04 '22 12:03 alexander-akait

@alexander-akait yeah, I found a problem.

vankop avatar Mar 04 '22 12:03 vankop

should work with https://github.com/webpack/webpack/discussions/15613

vankop avatar Apr 01 '22 13:04 vankop

Here is a reproducible project: webpack-mini-css-public-path-issue.zip

It works after upgrading webpack 5.71.0 + mini-css-extract-plugin 2.6.0.


My webpack.config.js is:

{
    test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
    type: 'asset/resource',
    generator: {
        publicPath: '//cdn.example.com/assets/',
        filename: `[name].[hash:8][ext]`
    }
}

But the output miss //:

$ cat dist/main.css
body {
  background-image: url(cdn.example.com/assets/webpack.1fcab817.svg);
}

scarletsky avatar Apr 02 '22 02:04 scarletsky

@vankop Still buggy?

alexander-akait avatar Apr 02 '22 10:04 alexander-akait

publicPath: '//cdn.example.com/assets/',

hm.. with one leading slash works fine..

vankop avatar Apr 02 '22 18:04 vankop