Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected output of url includes file:// protocol #1362

Closed
Fi2zz opened this issue Aug 24, 2021 · 26 comments
Closed

Unexpected output of url includes file:// protocol #1362

Fi2zz opened this issue Aug 24, 2021 · 26 comments

Comments

@Fi2zz
Copy link

Fi2zz commented Aug 24, 2021

  • Operating System: MacOS 11.4
  • Node Version: 16.3.0
  • NPM Version: 7.15.1
  • webpack Version: 5.41.1
  • css-loader Version: 6.2.0

Using default options of css-loader

transform background-image: url(../img/foo/bar.jpg) supposed to be background-image: url(/img/foo/bar.jpg)

but go background-image: url(file:///img/foo/bar.jpg),
please see the code below

the original css code

.Banner {
    height: 240px;
    background-image: **url(../assets/img/banner.jpg)**;
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    margin-bottom: 35px;
}

Expected Behavior

.Home_Banner__3Z7xi {
  height: 240px;
  background-image: **url(/33e75dae657057c9451f.jpg)**;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  display: -webkit-flex;
  display: flex;
  -webkit-align-items: center;
          align-items: center;
  -webkit-justify-content: center;
          justify-content: center;
  position: relative;
  margin-bottom: 35px;
}

Actual Behavior

.Home_Banner__3Z7xi {
  height: 240px;
  background-image: **url(file:///33e75dae657057c9451f.jpg)**;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  display: -webkit-flex;
  display: flex;
  -webkit-align-items: center;
          align-items: center;
  -webkit-justify-content: center;
          justify-content: center;
  position: relative;
  margin-bottom: 35px;
}

Code

// webpack.config.js

{
  test: /\.css$/,
 loader:require.resolve('css-loader')
}
@Fi2zz Fi2zz changed the title Unexpected output of url includes fille:// protocol Unexpected output of url includes file:// protocol Aug 24, 2021
@Fi2zz
Copy link
Author

Fi2zz commented Aug 24, 2021

problem solved by simply set options.esModule to false

@Fi2zz Fi2zz closed this as completed Aug 24, 2021
@alexander-akait
Copy link
Member

What is target? Which loader do you use too? options.esModule to false is dirty workaround

@cbazureau
Copy link

cbazureau commented Sep 9, 2021

I've got the same issue (target web).

For me there are strange changes on snapshots like here : 7ec5831#diff-667e298268e5db9f9f30c5a0b51b917e019a229d5ec4291f8435af819f4a64d7R276 (@cap-Bernardito / @alexander-akait)

In my case :

  • I've set an alias on assets: path.resolve(appRootPath, './src/assets/'),
  • I was previously using file-loader with a url('~assets/xxx/yyy.woff') syntax.
  • Now i've switched to type:assets/resource and the last css-loader version. i've tried
    • url('~assets/xxx/yyy.woff')
    • url('assets/xxx/yyy.woff')
    • url('/assets/xxx/yyy.woff')
    • url('../assets/xxx/yyy.woff') (relative path)

and i always get url('file://<my-output.path><filename-base-on-generator.filename') (for example file://client/yyy-1243523235.woff) instead of url('/<my-output.path><filename-base-on-generator.filename') (for example /client/yyy-1243523235.woff) like before

Edit : I need to update my https://github.com/webpack-contrib/mini-css-extract-plugin plugin. I'm trying this tomorrow and i'm telling you if it was the problem

@alexander-akait
Copy link
Member

Yes, we describe it, with css-loader v6 you need v2 (ideally the latest version) of mini-css-extract-plugin

@cbazureau
Copy link

cbazureau commented Sep 10, 2021

Yes it was that, i'm using a fork (webpack-contrib/mini-css-extract-plugin#711) so i didn't seen it first.

@alexander-akait
Copy link
Member

Why do you use fork?

@cbazureau
Copy link

cbazureau commented Sep 10, 2021

I've got a specific component in charge of loading async component (aka loading associated js/css/rtl-css in parallel) based on data collected by assets-webpack-plugin.
Like discuss here webpack-contrib/mini-css-extract-plugin#711. In my fork, i'm just removing some code from https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/src/index.js#L523 to https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/src/index.js#L817

  • i need the extraction provided by mini-css-extract-plugin (to get my .css files)
  • I'm using assets-webpack-plugin to get a json formated list of all assets grouped (js/css/rtl-css) by chunkname
  • my custom asyncCompoment can load onDemand component based on chunkname and the json generated previously
  • i know that it's "unsafe, because order can be wrong" (like you've said) but i've mitigated it using strict BEM declarations

@alexander-akait
Copy link
Member

Can you provide small example (need to check)? I think I know how you can solve this in a more correct direction.

@Fi2zz
Copy link
Author

Fi2zz commented Sep 10, 2021

workaround

I used the web target
After review ‘css-loader’ source code
It worked by simply set ‘options.esModule=false’

@alexander-akait
Copy link
Member

@Fi2zz update mini-css-extract-plugin

@Fi2zz
Copy link
Author

Fi2zz commented Sep 10, 2021

@Fi2zz update mini-css-extract-plugin

it generate file:// protocol before the plugin

@Fi2zz
Copy link
Author

Fi2zz commented Sep 10, 2021

@Fi2zz update mini-css-extract-plugin

Anyway, thank for help

@alexander-akait
Copy link
Member

@Fi2zz run npm ls mini-css-extract-plugin

@cbazureau
Copy link

cbazureau commented Sep 10, 2021

on my webpack :

plugins: [
       ...
       // Generates a JSON file containing a map of all the output files for
        // our webpack bundle.  A necessisty for our server rendering process
        // as we need to interogate these files in order to know what JS/CSS
        // we need to inject into our HTML.
      ifClient(
        new AssetsPlugin({
          filename: 'assets.json',
          path: path.resolve(appRootPath, './build/client/'),
        }),
      ),

     ifClient(
        // This is a production client so we will extract our CSS into
        // CSS files.
        new MiniCssExtractPlugin({
          filename: `${brandFirstLetter}-[name]-[contenthash].css`,
          chunkFilename: `${brandFirstLetter}-[name]-[contenthash].css`,
        }),
      ),

      ifClient(
        new WebpackRTLPlugin({
          filename: [/(\.css)/i, '-rtl$1'],
        }),
      ),
      ...
]
...
module: {
      rules: [
       ...
      // CSS
        merge(
          {
            test: /\.(scss|css)$/,
          },
          // For a production client build we use the MiniCssExtractPlugin which
          // will extract our CSS into CSS files.
          ifClient({
            use: [
              MiniCssExtractPlugin.loader,
              'css-loader',
              {
                loader: 'postcss-loader',
                options: {
                  postcssOptions: {
                    plugins: [require.resolve('autoprefixer')],
                  },
                },
              },
              { loader: 'sass-loader', options: { additionalData: beforeAllScss } },
              { loader: 'sass-resources-loader', options: { resources: beforeEachScss } },
            ],
          }),
          // When targetting the server we use the exportOnlyLocals version of the
          // css loader, as we don't need any css files for the server.
          ifServer({
            use: [
              {
                loader: 'css-loader',
                options: {
                  modules: {
                    exportOnlyLocals: true,
                  },
                },
              },
            ],
          }),
        ),
     ...
    ]

then AssetPlugin provides me almost what i'm set in my window.ASYNC_COMPONENTS_MAP which is something like

{
 ...
 'some-chunk': ['/client/r-some-chunk-hash.js', '/client/r-some-chunk-otherhash.css', false]
 ....
}

and when i need a chunk dynamically i'm doing


/**
  * getCssResolver
  */
 const getCssResolver = () => {
   // On browser side, check ASYNC_COMPONENTS_MAP which contains
   // chunk list with already resolved chunks.
   // If sharedState.chunkName isn't already resolved, download the css
   if (env === 'browser' && window.ASYNC_COMPONENTS_MAP) {
     const resolvedMap = window.ASYNC_COMPONENTS_MAP;
     const [, css, resolved] = resolvedMap[chunkName] || [];
     if (resolvedMap[chunkName] && css && resolved !== true) {
       return new Promise(resolveCSS => {
         resolvedMap[chunkName][2] = true;
         const myCSS = document.createElement('link');
         myCSS.rel = 'stylesheet';
         myCSS.href = css;
         myCSS.onload = () => {
           resolveCSS();
         };
         // insert it at the end of the head in a legacy-friendly manner
         if (document.head) {
           document.head.insertBefore(
             myCSS,
             document.head.childNodes[document.head.childNodes.length - 1].nextSibling,
           );
         }
       });
     }
   }
   return Promise.resolve();
 };

 /**
  * getModuleResolver
  */
 const getModuleResolver = () => {
   let resolver = null;

   const cssResolver = getCssResolver();
   try {
     resolver = Promise.resolve(resolve());
   } catch (err) {
     resolver = Promise.reject(err);
   }
   return Promise.all([resolver, cssResolver]);
 };

where resolve and chunkName are coming from the chunk declaration :

const SomeChunk = asyncComponent({
    chunkName: 'some-chunk',
    resolve: () =>
      import(
        /* webpackChunkName: "some-chunk" */ '../slices/SomeComponent'
      ),
  });

@alexander-akait
Copy link
Member

So you load async CSS chunks manually?

@cbazureau
Copy link

cbazureau commented Sep 10, 2021

So you load async CSS chunks manually?

Yes. JS + CSS (or RTL version of CSS depending the case)

@alexander-akait
Copy link
Member

I think here problem with WebpackRTLPlugin, it generate only assets, not chunks, so runtime is wrong...

@alexander-akait
Copy link
Member

Ideally WebpackRTLPlugin should modify output runtime generated code

@cbazureau
Copy link

cbazureau commented Sep 10, 2021

when i generate my HTML i'm changing my window.ASYNC_COMPONENTS_MAP from

{
 ...
 'some-chunk': ['/client/r-some-chunk-hash.js', '/client/r-some-chunk-otherhash.css', false]
 ....
}

to

{
 ...
 'some-chunk': ['/client/r-some-chunk-hash.js', '/client/r-some-chunk-otherhash-rtl.css', false]
 ....
}

on a RTL country
it works because i'm using the standard css hash for both css (it's pretty safe except when i'm updating WebpackRtlPlugin)

@alexander-akait
Copy link
Member

Yep, I see, you need modify generated runtime... Ideally it can be solved using plugin and it will be right solution

@cbazureau
Copy link

cbazureau commented Sep 10, 2021

My technical stack is up to date but highly customized so i'm not asking you (or someone) to change something on mini-css-extract-plugin or anywhere else. I think i am the only one to use mini-css-extract-plugin to just "extract css" 😉 and i'm rather have to adapt a well maintained plugin like mini-css-extract-plugin on each update than developing a new one.
Thx for the advice and for your great job on webpack !

@alexander-akait
Copy link
Member

@cbazureau in theory we can add flag noRuntime, and do not generate runtime, so you can only extract

@cbazureau
Copy link

yes if you agree to, i can push you a PR next week on mini-css-extract-plugin project

@alexander-akait
Copy link
Member

Yes, feel free to send, we just need to doc it, because it is very exotic

@kenrick95
Copy link

FYI for others encountering this bug: I found that this bug exist if we use css-loader (v6) + mini-css-extract-plugin (v2) with webpack <= 5.22.0. Found that bug will not exist anymore if webpack is upgraded to >= 5.23.0

Repro: https://github.com/kenrick95/css-loader-repro-file-protocol

@adidahiya
Copy link

adidahiya commented Apr 6, 2022

@kenrick95 thanks, this solved the problem for me. I was using css-loader v6.7.1, mini-css-extract-plugin v2.6.0, and webpack v5.21.0. I was getting my url('./relative-file.ttf') imports tranformed into this crazy string:

url('file:///.../node_modules/css-loader/dist/cjs.js%3F%3FruleSet[1].rules[2].use[1]!/.../node_modules/postcss-loader/dist/cjs.js%3F%3FruleSet[1].rules[2].use[2]!/.../node_modules/sass-loader/dist/cjs.js!/.../src/assets/relative-file.ttf')

(where ... is the absolute path to my project directory).

Upgrading webpack (now i'm on 5.71.0) fixed it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants