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

@import invalidates @charset declaration #1212

Open
markuslewin opened this issue Oct 19, 2020 · 19 comments
Open

@import invalidates @charset declaration #1212

markuslewin opened this issue Oct 19, 2020 · 19 comments

Comments

@markuslewin
Copy link

  • Operating System: Windows 10
  • Node Version: v14.14.0
  • NPM Version: 6.14.8
  • webpack Version: 5.1.3
  • css-loader Version: 5.0.0

Expected Behavior

The @charset declaration at the top of the generated CSS file.

Actual Behavior

The @charset declaration is below the imported CSS. To determine fallback encoding the @charset declaration must be at the start of the file (https://drafts.csswg.org/css-syntax-3/#determine-the-fallback-encoding).

The sass-loader automatically prepends @charset "UTF-8" (or BOM if in compressed mode). This information seems to be lost after sending the CSS string through the css-loader.

Code

Expected CSS:

@charset "utf-8";

p {
    color: red;
    font-size: 72px;
}

.greet::before {
    color: blue;
    content: 'Привет, ';
}

Actual CSS:

p {
    color: red;
    font-size: 72px;
}
@charset "utf-8";

.greet::before {
    color: blue;
    content: 'Привет, ';
}

How Do We Reproduce?

https://github.com/intemarkus/css-loader-charset-error

npm install
npm run build
Open dist/index.html in browser with file://.../css-loader-charset-error/dist/index.html

In some browsers (Chrome, IE, Edge) the CSS content isn't read as UTF-8.

The CSS file is generated with the MiniCssExtractPlugin, but the direct result of the css-loader is printed in the console window.

@alexander-akait
Copy link
Member

Do not use @charset, it is always utf-8 for webpack, but we should fix it

@SLKnutson
Copy link

It would be nice to have this fixed. Relying on returning the correct http headers is painful when hosting a static app.

@alexander-akait
Copy link
Member

We can't change your headers

@MitchTalmadge
Copy link

I'm having this problem too. A bunch of @font-face imports from open-sans are included before the @charset from sass-loader. I'm not sure what to do about this.

image

@markuslewin
Copy link
Author

As a workaround one could use a plugin such as https://github.com/cqqccqc/webpack-utf8-bom to prepend a UTF-8 BOM to the generated files.

@alexander-akait
Copy link
Member

Without webpack you will faced with the same issue, no problems on webpack side, modify src/index.html

<!DOCTYPE html>
<html>
    <head>
        <title>css-loader @charset error</title>
        <script defer src="./index.js"></script>
        <link href="./style-css-loader-only.css" rel="stylesheet">
    </head>
    <body>
        <p class="greet">Markus</p>
    </body>
</html>

How to fix? Just add <meta charset="UTF-8">, i.e.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>css-loader @charset error</title>
        <script defer src="./index.js"></script>
        <link href="./style-css-loader-only.css" rel="stylesheet">
    </head>
    <body>
        <p class="greet">Markus</p>
    </body>
</html>

@markuslewin
Copy link
Author

Yes! If you control the HTML you can set charset to UTF-8. If you control the server you can set the charset in the Content-Type HTTP header.

However, I ran into this issue when I tried to open a print popup in Safari. I had no control over the server, so I couldn't set any HTTP headers. On top of that, the <meta> tag seems to be ignored by Safari when the document is opened with window.open(). The encoding of the document is then determined by the Safari setting "Default encoding" which defaults to "Western (ISO Latin 1)".

I added the print popup to my repository. The CSS is served with an empty Content-Type header and the document that is opened in a new window contains <meta charset="UTF-8" />.

The problem is that in some (rare) cases I need to be able to specify the charset of the file in the CSS.

@MitchTalmadge
Copy link

Exactly, sometimes I do not have the ability to control the HTML or headers, and I must rely on this feature of CSS which is currently not usable.

Right now this plugin is resulting in CSS which is technically broken -- the charset tag cannot be placed in the middle of a file. Browsers are forgiving about this, but they will not parse the charset tag. Changing the HTML may be a solution for some people, but it does not fix the fact that the charset tag is in the middle of the file which is the primary problem here.

@alexander-akait
Copy link
Member

Converting from one charset to another is out of scope, you can write postcss plugin for this.

Changing the HTML may be a solution for some people, but it does not fix the fact that the charset tag is in the middle of the file which is the primary problem here.

Can you provide link/screenshot where tag in the middle, I can't reproduce using repo above

@markuslewin
Copy link
Author

markuslewin commented Mar 11, 2021

Updated my repo.

Without import:
without-import

With import:
with-import

@alexander-akait
Copy link
Member

Oh, I see

@xqk1
Copy link

xqk1 commented Jun 1, 2021

The same problem

clydin pushed a commit to angular/angular-cli that referenced this issue Nov 8, 2021
…irst rule in the file warning

esbuild will issue a warning when `@charset` is in the middle of the file. This is caused by css-loader will concats the file and doesn't hoist `@charset`, (webpack-contrib/css-loader#1212).

While, esbuild will issue a warning regarding the above, it will hoist to the very top.

In many cases, this warning is not actionable by the users as the `@charset` would be likely specified in 3rd party libs.

Closes #22097

(cherry picked from commit b3e5888)
clydin pushed a commit to angular/angular-cli that referenced this issue Nov 8, 2021
…irst rule in the file warning

esbuild will issue a warning when `@charset` is in the middle of the file. This is caused by css-loader will concats the file and doesn't hoist `@charset`, (webpack-contrib/css-loader#1212).

While, esbuild will issue a warning regarding the above, it will hoist to the very top.

In many cases, this warning is not actionable by the users as the `@charset` would be likely specified in 3rd party libs.

Closes #22097
@sirsimon
Copy link

sirsimon commented Feb 4, 2022

I have the same problem

@alessandro308
Copy link

Any news on that?

@ArtemNikolaev
Copy link

Have same issue when trying to add bundled bootstrap css, so there's no way i can just remove it from my css, because it's not my css

@ericwfisher
Copy link

Are there plans to address this?

@alexander-akait
Copy link
Member

alexander-akait commented Nov 16, 2022

The only possible solution is removing @charset "utf-8";, you can solve it on postcss-loader level, just simple plugin, we can't move @charset at the top, because you can have more modules and we don't know the final order of them (you can always load them dynamically)

@alexander-akait
Copy link
Member

alexander-akait commented Nov 16, 2022

But removing is not safe, because if you have characters which are more them ascii they will be broken, but now they are broken too 😄

@mikekscholz
Copy link

For anyone else trying to deal with this I made it go away by adding charset: false to my sass options in webpack.config.js
At the very least its a step in figuring out which package is the cause, looking like sass itself.

  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/i,
        use: [
          MiniCssExtractPlugin.loader,
          "css-loader",
          "postcss-loader",
          {
            loader: "sass-loader",
            options: {
              sassOptions: {
                charset: false
              },
              // Prefer `dart-sass`
              implementation: require("sass"),
            },
          }
        ],
      },
    ],
  }

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

No branches or pull requests

10 participants