Skip to content

Commit

Permalink
feat(html): add hash config and refactor code to pass test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
LingyuCoder committed Aug 14, 2024
1 parent 25732d9 commit 96a0822
Show file tree
Hide file tree
Showing 12 changed files with 360 additions and 303 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1244,12 +1244,13 @@ export interface RawHtmlRspackPluginOptions {
scriptLoading: "blocking" | "defer" | "module"
/** entry_chunk_name (only entry chunks are supported) */
chunks?: Array<string>
excludedChunks?: Array<string>
excludeChunks?: Array<string>
sri?: "sha256" | "sha384" | "sha512"
minify?: boolean
title?: string
favicon?: string
meta?: Record<string, Record<string, string>>
hash?: boolean
}

export interface RawHttpExternalsRspackPluginOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ pub struct RawHtmlRspackPluginOptions {

/// entry_chunk_name (only entry chunks are supported)
pub chunks: Option<Vec<String>>,
pub excluded_chunks: Option<Vec<String>>,
pub exclude_chunks: Option<Vec<String>>,
#[napi(ts_type = "\"sha256\" | \"sha384\" | \"sha512\"")]
pub sri: Option<RawHtmlSriHashFunction>,
pub minify: Option<bool>,
pub title: Option<String>,
pub favicon: Option<String>,
pub meta: Option<HashMap<String, HashMap<String, String>>>,
pub hash: Option<bool>,
}

impl From<RawHtmlRspackPluginOptions> for HtmlRspackPluginOptions {
Expand All @@ -62,12 +63,13 @@ impl From<RawHtmlRspackPluginOptions> for HtmlRspackPluginOptions {
public_path: value.public_path,
script_loading,
chunks: value.chunks,
excluded_chunks: value.excluded_chunks,
exclude_chunks: value.exclude_chunks,
sri,
minify: value.minify.unwrap_or_default(),
title: value.title,
favicon: value.favicon,
meta: value.meta,
hash: value.hash.unwrap_or_default(),
}
}
}
1 change: 1 addition & 0 deletions crates/rspack_plugin_html/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ swc_core = { workspace = true }
swc_html = { workspace = true }
swc_html_minifier = { workspace = true }
tracing = { workspace = true }
urlencoding = { workspace = true }

[package.metadata.cargo-shear]
ignored = ["tracing"]
6 changes: 4 additions & 2 deletions crates/rspack_plugin_html/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub struct HtmlRspackPluginOptions {

/// entry_chunk_name (only entry chunks are supported)
pub chunks: Option<Vec<String>>,
pub excluded_chunks: Option<Vec<String>>,
pub exclude_chunks: Option<Vec<String>>,

/// hash func that used in subsource integrity
/// sha384, sha256 or sha512
Expand All @@ -94,6 +94,7 @@ pub struct HtmlRspackPluginOptions {
pub title: Option<String>,
pub favicon: Option<String>,
pub meta: Option<HashMap<String, HashMap<String, String>>>,
pub hash: bool,
}

fn default_filename() -> String {
Expand All @@ -119,12 +120,13 @@ impl Default for HtmlRspackPluginOptions {
public_path: None,
script_loading: default_script_loading(),
chunks: None,
excluded_chunks: None,
exclude_chunks: None,
sri: None,
minify: false,
title: None,
favicon: None,
meta: None,
hash: false,
}
}
}
Expand Down
52 changes: 45 additions & 7 deletions crates/rspack_plugin_html/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::{

use anyhow::Context;
use dojang::dojang::Dojang;
use itertools::Itertools;
use rayon::prelude::*;
use rspack_core::{
parse_to_url,
Expand All @@ -22,7 +23,10 @@ use crate::{
config::{HtmlInject, HtmlRspackPluginOptions},
parser::HtmlCompiler,
sri::{add_sri, create_digest_from_asset},
visitors::asset::{AssetWriter, HTMLPluginTag},
visitors::{
asset::{AssetWriter, HTMLPluginTag},
utils::append_hash,
},
};

#[plugin]
Expand Down Expand Up @@ -100,8 +104,8 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
if let Some(included_chunks) = &config.chunks {
included = included_chunks.iter().any(|c| c.eq(entry_name));
}
if let Some(excluded_chunks) = &config.excluded_chunks {
included = included && !excluded_chunks.iter().any(|c| c.eq(entry_name));
if let Some(exclude_chunks) = &config.exclude_chunks {
included = included && !exclude_chunks.iter().any(|c| c.eq(entry_name));
}
included
})
Expand All @@ -121,11 +125,19 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
// if inject is 'false', don't do anything
if !matches!(config.inject, HtmlInject::False) {
for (asset_name, asset) in included_assets {
if let Some(extension) = Path::new(&asset_name).extension() {
let asset_uri = format!(
"{}{asset_name}",
if let Some(extension) =
Path::new(asset_name.split("?").next().unwrap_or_default()).extension()
{
let mut asset_uri = format!(
"{}{}",
config.get_public_path(compilation, &self.config.filename),
url_encode_path(&asset_name)
);
if config.hash {
if let Some(hash) = compilation.get_hash() {
asset_uri = append_hash(&asset_uri, hash);
}
}
let mut tag: Option<HTMLPluginTag> = None;
if extension.eq_ignore_ascii_case("css") {
tag = Some(HTMLPluginTag::create_style(&asset_uri, HtmlInject::Head));
Expand Down Expand Up @@ -160,7 +172,9 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> {
let mut visitor = AssetWriter::new(config, &tags, compilation);
current_ast.visit_mut_with(&mut visitor);

let source = parser.codegen(&mut current_ast)?;
let source = parser
.codegen(&mut current_ast)?
.replace("$$RSPACK_URL_AMP$$", "&");
let hash = hash_for_source(&source);
let html_file_name = FilenameTemplate::from(config.filename.clone());
// Use the same filename as template
Expand Down Expand Up @@ -243,3 +257,27 @@ fn hash_for_source(source: &str) -> String {
source.hash(&mut hasher);
format!("{:016x}", hasher.finish())
}

fn url_encode_path(file_path: &str) -> String {
let query_string_start = file_path.find('?');
let url_path = if let Some(query_string_start) = query_string_start {
file_path[..query_string_start].to_string()
} else {
file_path.to_string()
};
let query_string = if let Some(query_string_start) = query_string_start {
file_path[query_string_start..].to_string()
} else {
"".to_string()
};

format!(
"{}{}",
url_path
.split('/')
.map(|p| { urlencoding::encode(p) })
.join("/"),
// element.outerHTML will escape '&' so need to add a placeholder here
query_string.replace("&", "$$RSPACK_URL_AMP$$")
)
}
8 changes: 7 additions & 1 deletion crates/rspack_plugin_html/src/visitors/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use swc_core::{common::DUMMY_SP, ecma::atoms::Atom};
use swc_html::ast::{Attribute, Child, Element, Namespace, Text};
use swc_html::visit::{VisitMut, VisitMutWith};

use super::utils::create_element;
use super::utils::{append_hash, create_element};
use crate::config::{HtmlInject, HtmlRspackPluginOptions, HtmlScriptLoading};

// the tag
Expand Down Expand Up @@ -185,6 +185,12 @@ impl VisitMut for AssetWriter<'_, '_> {
favicon_link_path = reg.replace_all(favicon_link_path.as_str(), "/").to_string();
}

if self.config.hash {
if let Some(hash) = self.compilation.get_hash() {
favicon_link_path = append_hash(&favicon_link_path, hash);
}
}

n.children.push(Child::Element(Element {
tag_name: Atom::from("link"),
children: vec![],
Expand Down
2 changes: 1 addition & 1 deletion crates/rspack_plugin_html/src/visitors/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pub mod asset;
mod utils;
pub mod utils;
15 changes: 14 additions & 1 deletion crates/rspack_plugin_html/src/visitors/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub fn create_attribute(name: &str, value: &Option<String>) -> Attribute {
name: name.into(),
raw_name: None,
value: value.as_ref().map(|str| Atom::from(str.as_str())),
raw_value: None,
raw_value: value.as_ref().map(|str| Atom::from(str.as_str())),
}
}

Expand All @@ -33,3 +33,16 @@ pub fn create_element(tag: &HTMLPluginTag) -> Element {
span: DUMMY_SP,
}
}

pub fn append_hash(url: &str, hash: &str) -> String {
format!(
"{}{}{}",
url,
if url.contains("?") {
"$$RSPACK_URL_AMP$$"
} else {
"?"
},
hash
)
}
15 changes: 10 additions & 5 deletions packages/rspack/etc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4587,13 +4587,14 @@ export const HtmlRspackPlugin: {
new (c?: {
filename?: string | undefined;
publicPath?: string | undefined;
hash?: boolean | undefined;
chunks?: string[] | undefined;
template?: string | undefined;
templateContent?: string | undefined;
templateParameters?: Record<string, string> | undefined;
inject?: boolean | "head" | "body" | undefined;
scriptLoading?: "module" | "blocking" | "defer" | undefined;
excludedChunks?: string[] | undefined;
excludeChunks?: string[] | undefined;
sri?: "sha256" | "sha384" | "sha512" | undefined;
minify?: boolean | undefined;
title?: string | undefined;
Expand All @@ -4604,13 +4605,14 @@ export const HtmlRspackPlugin: {
_args: [c?: {
filename?: string | undefined;
publicPath?: string | undefined;
hash?: boolean | undefined;
chunks?: string[] | undefined;
template?: string | undefined;
templateContent?: string | undefined;
templateParameters?: Record<string, string> | undefined;
inject?: boolean | "head" | "body" | undefined;
scriptLoading?: "module" | "blocking" | "defer" | undefined;
excludedChunks?: string[] | undefined;
excludeChunks?: string[] | undefined;
sri?: "sha256" | "sha384" | "sha512" | undefined;
minify?: boolean | undefined;
title?: string | undefined;
Expand All @@ -4636,22 +4638,24 @@ const htmlRspackPluginOptions: z.ZodObject<{
publicPath: z.ZodOptional<z.ZodString>;
scriptLoading: z.ZodOptional<z.ZodEnum<["blocking", "defer", "module"]>>;
chunks: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
excludedChunks: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
excludeChunks: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
sri: z.ZodOptional<z.ZodEnum<["sha256", "sha384", "sha512"]>>;
minify: z.ZodOptional<z.ZodBoolean>;
title: z.ZodOptional<z.ZodString>;
favicon: z.ZodOptional<z.ZodString>;
meta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>]>>>;
hash: z.ZodOptional<z.ZodBoolean>;
}, "strict", z.ZodTypeAny, {
filename?: string | undefined;
publicPath?: string | undefined;
hash?: boolean | undefined;
chunks?: string[] | undefined;
template?: string | undefined;
templateContent?: string | undefined;
templateParameters?: Record<string, string> | undefined;
inject?: boolean | "head" | "body" | undefined;
scriptLoading?: "module" | "blocking" | "defer" | undefined;
excludedChunks?: string[] | undefined;
excludeChunks?: string[] | undefined;
sri?: "sha256" | "sha384" | "sha512" | undefined;
minify?: boolean | undefined;
title?: string | undefined;
Expand All @@ -4660,13 +4664,14 @@ const htmlRspackPluginOptions: z.ZodObject<{
}, {
filename?: string | undefined;
publicPath?: string | undefined;
hash?: boolean | undefined;
chunks?: string[] | undefined;
template?: string | undefined;
templateContent?: string | undefined;
templateParameters?: Record<string, string> | undefined;
inject?: boolean | "head" | "body" | undefined;
scriptLoading?: "module" | "blocking" | "defer" | undefined;
excludedChunks?: string[] | undefined;
excludeChunks?: string[] | undefined;
sri?: "sha256" | "sha384" | "sha512" | undefined;
minify?: boolean | undefined;
title?: string | undefined;
Expand Down
5 changes: 3 additions & 2 deletions packages/rspack/src/builtin-plugin/HtmlRspackPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ const htmlRspackPluginOptions = z.strictObject({
publicPath: z.string().optional(),
scriptLoading: z.enum(["blocking", "defer", "module"]).optional(),
chunks: z.string().array().optional(),
excludedChunks: z.string().array().optional(),
excludeChunks: z.string().array().optional(),
sri: z.enum(["sha256", "sha384", "sha512"]).optional(),
minify: z.boolean().optional(),
title: z.string().optional(),
favicon: z.string().optional(),
meta: z.record(z.string().or(z.record(z.string()))).optional()
meta: z.record(z.string().or(z.record(z.string()))).optional(),
hash: z.boolean().optional()
});
export type HtmlRspackPluginOptions = z.infer<typeof htmlRspackPluginOptions>;
export const HtmlRspackPlugin = create(
Expand Down
Loading

0 comments on commit 96a0822

Please sign in to comment.