vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.02k stars 26.7k forks source link

SCSS Url Static Assets Failing to load #70021

Open theblondealex opened 6 days ago

theblondealex commented 6 days ago

Link to the code that reproduces this issue

https://github.com/theblondealex/scss-reproduction

To Reproduce

  1. Clone the repo
  2. Install dependencies
  3. Run the dev server
  4. Open the browser at http://localhost:3000
  5. Go to the src/app/page.tsx file
  6. Comment out the import of the css file and uncomment the import of the scss file
  7. You will notice that the svg is not rendered when using the scss file but it is rendered when using the css file

Current vs. Expected behavior

You will see that if the react-example is ran, the scss file is interpreted and works correctly.

Expected is that nextjs should render the url(svgs) correctly

SCSS is installed correctly as the styles are applied just not the svg loaded

Normal image works correctly in the url it is specific to .svg#ID sprite svgs

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #40~22.04.3-Ubuntu SMP PREEMPT_DYNAMIC Tue Jul 30 17:30:19 UTC 2
  Available memory (MB): 31546
  Available CPU cores: 14
Binaries:
  Node: 22.4.0
  npm: 10.8.1
  Yarn: 1.22.22
  pnpm: N/A
Relevant Packages:
  next: 14.2.10 // Latest available version is detected (14.2.10).
  eslint-config-next: 14.2.10
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.6.2
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Not sure, Middleware, Output (export/standalone)

Which stage(s) are affected? (Select all that apply)

next dev (local), next build (local), next start (local), Vercel (Deployed), Other (Deployed)

Additional context

No response

abhi12299 commented 6 days ago

The nextjs version is stripping out the #passport part from the background url. In sass, if the property is: background: url('./svgs/output/all-svgs-sprite.svg#passport') no-repeat;, the output css becomes background: url('./svgs/output/all-svgs-sprite.svg') no-repeat;.

Since the css files are processed correctly, I believe the sass-loader config used internally by nextjs is messing up things.

theblondealex commented 6 days ago

The nextjs version is stripping out the #passport part from the background url. In sass, if the property is: background: url('./svgs/output/all-svgs-sprite.svg#passport') no-repeat;, the output css becomes background: url('./svgs/output/all-svgs-sprite.svg') no-repeat;.

Since the css files are processed correctly, I believe the sass-loader config used internally by nextjs is messing up things.

Yes this is my thinking too

theblondealex commented 6 days ago

I belive the issue lies here

    const lazyPostCSSInitializer = ()=>lazyPostCSS(ctx.rootDirectory, ctx.supportedBrowsers, ctx.experimental.disablePostcssPresetEnv);
    const sassPreprocessors = [
        // First, process files with `sass-loader`: this inlines content, and
        // compiles away the proprietary syntax.
        {
            loader: require.resolve("next/dist/compiled/sass-loader"),
            options: {
                // Source maps are required so that `resolve-url-loader` can locate
                // files original to their source directory.
                sourceMap: true,
                sassOptions: {
                    // The "fibers" option is not needed for Node.js 16+, but it's causing
                    // problems for Node.js <= 14 users as you'll have to manually install
                    // the `fibers` package:
                    // https://github.com/webpack-contrib/sass-loader#:~:text=We%20automatically%20inject%20the%20fibers%20package
                    // https://github.com/vercel/next.js/issues/45052
                    // Since it's optional and not required, we'll disable it by default
                    // to avoid the confusion.
                    fibers: false,
                    ...sassOptions
                },
                additionalData: sassPrependData || sassAdditionalData
            }
        },
        // Then, `sass-loader` will have passed-through CSS imports as-is instead
        // of inlining them. Because they were inlined, the paths are no longer
        // correct.
        // To fix this, we use `resolve-url-loader` to rewrite the CSS
        // imports to real file paths.
        {
            loader: require.resolve("../../../loaders/resolve-url-loader/index"),
            options: {
                postcss: lazyPostCSSInitializer,
                // Source maps are not required here, but we may as well emit
                // them.
                sourceMap: true
            }
        }
    ];
    const fns = [];

sass-loader here recommends putting the resolve-url-loader before the sass-loader but that causes next to fail

abhi12299 commented 6 days ago

moved the resolve-url-loader before the sass-loader. got this error:

Error: resolve-url-loader: CSS error
  file://scss-reproduction/nextjs/src/app/page.scss:6:6: Unknown word
You tried to parse SCSS with the standard CSS parser; try again with the postcss-scss parser
  You tried to parse SCSS with the standard CSS parser; try again with the postcss-scss parser