web-infra-dev / rspack

The fast Rust-based web bundler with webpack-compatible API 🦀️
https://rspack.dev
MIT License
9.36k stars 543 forks source link

Builtin html encodes title to html entities #3770

Closed felixmosh closed 1 month ago

felixmosh commented 1 year ago

System Info

System: OS: macOS 13.4.1 CPU: (12) x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz Memory: 810.68 MB / 16.00 GB Shell: 5.9 - /bin/zsh Binaries: Node: 16.16.0 - ~/Library/Caches/fnm_multishells/39009_1689231227850/bin/node Yarn: 1.22.19 - ~/.yarn/bin/yarn npm: 9.6.7 - /usr/local/bin/npm Watchman: 2023.04.17.00 - /usr/local/bin/watchman Browsers: Chrome: 114.0.5735.198 Firefox: 114.0.2 Safari: 16.5.1

Details

Having a ejs as a html template

<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <meta name="robots" content="noindex" />
    <base href="<%= basePath %>" />
    <title><%= title %></title>
    <link rel="alternate icon" type="image/png" href="<%= favIconAlternative %>">
    <link rel="icon" type="image/svg+xml" id="fav-logo" href="<%= favIconDefault %>">
    <link href="https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500&display=swap" rel="stylesheet">
</head>
<body>
<script id="__UI_CONFIG__" type="application/json"><%- uiConfig %></script>
<div id="root">Loading...</div>
</body>
</html>

With the following rspack html config

// rspack.config.js
html: [
      {
        template: './src/index.ejs',
        filename: '../index.ejs',
        publicPath: 'static/',
      },
    ]

Encodes the title ejs bracks to <title>&lt;title&gt;</title> event if I didn't provided templateParameters at all.

Reproduce link

No response

Reproduce Steps

  1. yarn create rspack
  2. create a index.ejs file with the content above
  3. update rspack.config.js file with the html builtin block with the content above.
  4. start the project
kanweiwei commented 1 year ago

I am interested in fixing this issue

hyf0 commented 1 year ago

I am interested in fixing this issue

Thank you in advance.

stale[bot] commented 12 months ago

This issue has been automatically marked as stale because it has not had recent activity. If this issue is still affecting you, please leave any comment (for example, "bump"). We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

hardfist commented 12 months ago

bump

suxin2017 commented 9 months ago

Seems to be an issue with upstream dependencies webpack will give a ReferenceError: title is not defined when it can't find the variable. I think this is a capability of ejs. But when dojang couldn't find the variable, the value of the variable was false

I think we should expect the same error as webpack, to tell us that the variable isn't defined

felixmosh commented 9 months ago

It is not related, there is a value for this param, but it's value contains <> which gets encoded for some reason.

suxin2017 commented 9 months ago

The one you mentioned was made by swc-html https://github.com/swc-project/swc/blob/d883c13d3d27ba1e1ff49ce65599ac7040cc52e0/crates/swc_html_codegen/src/lib.rs#L1111C1-L1162C1

because it didn't use ejs template parsing, so <%= title %> Not replaced with var title In webpack you get an error warning "RefrenceError: title is not define"

// output index.html
Html Webpack Plugin:
<pre>
  ReferenceError: title is not defined

So what comes out is what you see. "<%= title %>" It becomes <%= title %&gt

felixmosh commented 9 months ago

Forget about ejs, if my template has <title><%= title></title> it get's encoded, in webpack html plugin it doesn't.

stale[bot] commented 7 months ago

This issue has been automatically marked as stale because it has not had recent activity. If this issue is still affecting you, please leave any comment (for example, "bump"). We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

felixmosh commented 7 months ago

Bump

stale[bot] commented 5 months ago

This issue has been automatically marked as stale because it has not had recent activity. If this issue is still affecting you, please leave any comment (for example, "bump"). We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

wxiaoyun commented 3 months ago

This is caused by not providing templateParameters in the HtmlRspackPlugin config.

In the rust code, since config.template_parameters matches to None variant of Result, the Dojang logic is completely skipped:

  // process with template parameters
  let template_result = if let Some(template_parameters) = &self.config.template_parameters {
    let mut dj = Dojang::new();
    dj.add(url.clone(), content)
      .expect("failed to add template");
    dj.render(&url, serde_json::json!(template_parameters))
      .expect("failed to render template")
  } else {
    content
  };

This is the reason why the emitted .ejs file is almost identical to the original. To work around this, we can default to dj.render(&url, serde_json::json!({}) in the None branch.

If the desired behavior is to raise a runtime exception, this is not possible since Dojang will replace all parameters that are not provided with false even if the parameter is not provided (see Dojang source code Context::get_value):

use dojang::Dojang;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut dj = Dojang::new();

    dj.add(
        "output.html".into(),
        r#"
        <!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
    <meta name="robots" content="noindex" />
    <base href="<%= basePath %>" />
    <title><%= title %></title>
    <link
      rel="alternate icon"
      type="image/png"
      href="<%= favIconAlternative %>"
    />
    <link
      rel="icon"
      type="image/svg+xml"
      id="fav-logo"
      href="<%= favIconDefault %>"
    />
    <link
      href="https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500&display=swap"
      rel="stylesheet"
    />
  </head>
  <body>
    <script id="__UI_CONFIG__" type="application/json">
      <%- uiConfig %>
    </script>
    <div id="root">Loading...</div>
  </body>
</html>
      "#
        .into(),
    )?;

    let res = dj.render(
        "output.html",
        serde_json::json!({
            // "basePath": "/",
            // "title": "My App",
            // "favIconAlternative": "path/to/alternative/favicon.png",
            // "favIconDefault": "path/to/default/favicon.svg"
        }),
    )?;

    println!("{}", res);

    Ok(())
}

Output:

>  cargo run
   Compiling errorrspack v0.1.0 (/Users/bytedance/dev/errorrspack)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
     Running `target/debug/errorrspack`

        <!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
    <meta name="robots" content="noindex" />
    <base href="false" />
    <title>false</title>
    <link
      rel="alternate icon"
      type="image/png"
      href="false"
    />
    <link
      rel="icon"
      type="image/svg+xml"
      id="fav-logo"
      href="false"
    />
    <link
      href="https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500&display=swap"
      rel="stylesheet"
    />
  </head>
  <body>
    <script id="__UI_CONFIG__" type="application/json">
      false
    </script>
    <div id="root">Loading...</div>
  </body>
</html>