Skip to content

Commit

Permalink
feat: change in hash generation method for FILE_ID (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
taishinaritomi authored Aug 25, 2023
1 parent 112b1e4 commit 2f59bf8
Show file tree
Hide file tree
Showing 12 changed files with 184 additions and 90 deletions.
6 changes: 6 additions & 0 deletions .changeset/cool-impalas-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@excss/compiler": patch
"excss": patch
---

feat: change in hash generation method for FILE_ID
7 changes: 7 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ getrandom = "0.2"
grass = "0.13"
grass_compiler = "0.13"
itertools = "0.9"
pathdiff = "0.2"
scoped-tls = "1.0"
serde = "1"
serde_json = "1"
Expand Down
1 change: 1 addition & 0 deletions packages/compiler/crates/compiler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ serde_json = { workspace = true }
getrandom = { workspace = true, features = ["js"] }
grass = { workspace = true }
grass_compiler = { workspace = true }
pathdiff = { workspace = true }
swc_core = { workspace = true, features = [
"ecma_transforms_typescript",
"ecma_transforms_react",
Expand Down
14 changes: 7 additions & 7 deletions packages/compiler/crates/compiler/src/compiler/compile_css.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ scoped_thread_local!(static CONTEXT: Context);

struct Context {
count: Mutex<usize>,
hash_prefix: String,
unique_salt: String,
}

impl Context {
fn new(hash_prefix: String) -> Self {
fn new(unique_salt: String) -> Self {
Self {
unique_salt,
count: Mutex::new(0),
hash_prefix,
}
}

Expand All @@ -31,7 +31,7 @@ impl Context {

fn get_unique_hash(&self) -> Result<String, io::Error> {
let count = self.get_unique_count();
let hash_input = format!("{}{}", self.hash_prefix, count);
let hash_input = format!("{}+{}", self.unique_salt, count);
generate_hash(&hash_input)
}
}
Expand All @@ -52,13 +52,13 @@ pub struct Output {
pub fn compile<T: Into<String>>(
input: T,
inject: T,
hash_prefix: T,
unique_salt: T,
) -> Result<Output, Box<dyn Error>> {
let input = input.into();
let inject = inject.into();
let hash_prefix = hash_prefix.into();
let unique_salt: String = unique_salt.into();

let result = CONTEXT.set(&Context::new(hash_prefix), || {
let result = CONTEXT.set(&Context::new(unique_salt), || {
let option = grass::Options::default()
.input_syntax(grass::InputSyntax::Scss)
.add_custom_fn("unique", Builtin::new(unique));
Expand Down
136 changes: 79 additions & 57 deletions packages/compiler/crates/compiler/src/transform.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use pathdiff::diff_paths;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::{collections::BTreeMap, io, path::Path};
use swc_core::ecma::visit::VisitMutWith;

use super::{
Expand All @@ -13,10 +14,14 @@ const IMPORT_SOURCE: &str = "excss";
const IMPORT_CSS_IDENT: &str = "css";
const IMPORT_FILE_ID_IDENT: &str = "FILE_ID";
const CSS_FILE_ID_VARIANT: &str = "FILE_ID";
const DEFAULT_PACKAGE_NAME: &str = "unknown";

#[derive(Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Config {
pub filename: String,
pub root: Option<String>,
pub package_name: Option<String>,
pub inject: Option<String>,
pub variants: Option<compile_css_variants::Variants>,
}
Expand All @@ -28,64 +33,81 @@ pub struct Output {
pub css: String,
}

fn get_file_id(
filename: String,
root: Option<String>,
package_name: Option<String>,
) -> Result<String, io::Error> {
let resolved_path = root
.and_then(|root| {
let path = Path::new(&filename);
diff_paths(path, root).map(|path| path.display().to_string())
})
.unwrap_or(filename);

let package_name = &package_name.unwrap_or(DEFAULT_PACKAGE_NAME.to_string());

generate_hash(&format!("{}+{}", package_name, &resolved_path))
}

pub fn transform(code: String, config: Config) -> Result<Output, error::Error> {
match generate_hash(&config.filename) {
Ok(file_id) => {
let mut css = String::new();

let mut variants = config.variants.unwrap_or(BTreeMap::new());

variants.insert(
CSS_FILE_ID_VARIANT.to_string(),
compile_css_variants::VariantValue::Str(file_id.clone()),
);

let inject_css = format!(
"{}\n{}",
compile_css_variants::compile(&variants),
config.inject.unwrap_or(String::new())
);

let import_source = &IMPORT_SOURCE.to_string();
let import_css_ident = &IMPORT_CSS_IDENT.to_string();
let import_file_id_ident = &IMPORT_FILE_ID_IDENT.to_string();

let compile_input = compile_js::Input {
code,
filename: &config.filename,
};

let result = compile_js::compile(compile_input, |(module, _)| {
let mut module = module;

let mut transform_visitor = TransformVisitor::new(
import_source,
import_css_ident,
import_file_id_ident,
&file_id,
&inject_css,
);

module.visit_mut_with(&mut transform_visitor);

css = transform_visitor.get_css();

module
});

match result {
Ok(result) => Ok(Output {
code: result.code,
map: result.map,
css,
}),
Err(err) => Err(error::Error { errors: err.errors }),
let file_id =
get_file_id(config.filename.clone(), config.root, config.package_name).map_err(|err| {
error::Error {
errors: vec![error::Diagnostic {
message: err.to_string(),
}],
}
}
Err(err) => Err(error::Error {
errors: vec![error::Diagnostic {
message: err.to_string(),
}],
})?;

let mut css = String::new();

let mut variants = config.variants.unwrap_or(BTreeMap::new());

variants.insert(
CSS_FILE_ID_VARIANT.to_string(),
compile_css_variants::VariantValue::Str(file_id.clone()),
);

let inject_css = format!(
"{}\n{}",
compile_css_variants::compile(&variants),
config.inject.unwrap_or(String::new())
);

let import_source = &IMPORT_SOURCE.to_string();
let import_css_ident = &IMPORT_CSS_IDENT.to_string();
let import_file_id_ident = &IMPORT_FILE_ID_IDENT.to_string();

let compile_input = compile_js::Input {
code,
filename: &config.filename,
};

let result = compile_js::compile(compile_input, |(module, _)| {
let mut module = module;

let mut transform_visitor = TransformVisitor::new(
import_source,
import_css_ident,
import_file_id_ident,
&file_id,
&inject_css,
);

module.visit_mut_with(&mut transform_visitor);

css = transform_visitor.get_css();

module
});

match result {
Ok(result) => Ok(Output {
code: result.code,
map: result.map,
css,
}),
Err(err) => Err(error::Error { errors: err.errors }),
}
}
29 changes: 9 additions & 20 deletions packages/compiler/crates/compiler/src/visitor/transform_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ use swc_core::{
},
};

use crate::{
compiler::compile_css, hash::generate_hash, visitor::search_import_visitor::SearchImportVisitor,
};
use crate::{compiler::compile_css, visitor::search_import_visitor::SearchImportVisitor};

pub struct TransformVisitor<'a> {
target_css_ident_ids: Vec<ast::Id>,
Expand Down Expand Up @@ -129,25 +127,16 @@ impl VisitMut for TransformVisitor<'_> {
let mut class_name = "".to_string();

if !css.is_empty() {
let hash_input = format!("{}{}", &self.file_id, &self.hash_count);
let hash_salt = format!("{}+{}", &self.file_id, &self.hash_count);
self.hash_count += 1;

let css_hash = generate_hash(&hash_input)
.map_err(|err| {
match compile_css::compile(css, self.inject_css.clone(), hash_salt) {
Ok(output) => {
class_name = output.class_name;
self.css_list.insert(output.css);
}
Err(err) => {
errors::HANDLER.with(|h| h.err(&err.to_string()));
})
.ok();

if let Some(css_hash) = css_hash {
self.hash_count += 1;

match compile_css::compile(css, self.inject_css.clone(), css_hash) {
Ok(output) => {
class_name = output.class_name;
self.css_list.insert(output.css);
}
Err(err) => {
errors::HANDLER.with(|h| h.err(&err.to_string()));
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion packages/compiler/crates/compiler_wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ extern crate console_error_panic_hook;
const TYPES: &'static str = r#"
export type Config = {
filename: string;
root?: string | undefined;
packageName?: string | undefined;
inject?: string | undefined;
variants?: Record<string, string | number> | undefined;
variants?: Variants | undefined;
}
export type Result = {
Expand Down
19 changes: 19 additions & 0 deletions packages/excss/src/plugins/vite.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import fs from "node:fs";
import path from "node:path";
import type { Variants } from "@excss/compiler";
import { transform } from "@excss/compiler";
import type * as Vite from "vite";
Expand Down Expand Up @@ -35,9 +37,24 @@ function excss(option?: ExcssOption): Vite.Plugin {
option?.exclude,
);

let root: string;
let packageName: string | undefined;

return {
name: "excss",

configResolved(viteConfig) {
root = viteConfig.root;
const packageJson = JSON.parse(
fs.readFileSync(path.join(root, "package.json")).toString(),
) as { name?: string };

console.log(packageJson.name);

viteConfig.configFileDependencies.push("package.json");
packageName = packageJson.name;
},

resolveId(id) {
const [filename, params] = id.split("?");
return filename === VIRTUAL_MODULE_ID
Expand Down Expand Up @@ -66,6 +83,8 @@ function excss(option?: ExcssOption): Vite.Plugin {

const result = transform(code, {
filename,
root,
packageName,
variants: option?.variants,
inject: option?.inject,
});
Expand Down
15 changes: 14 additions & 1 deletion packages/excss/src/plugins/webpack/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,39 @@ export type ExcssLoaderOption = {
cssOutDir?: string | undefined;
variants?: Variants | undefined;
inject?: string | undefined;
packageName?: string | undefined;
configDependencies?: string[] | undefined;
};

function excssLoader(
this: LoaderContext<ExcssLoaderOption>,
code: WebpackLoaderParams[0],
map: WebpackLoaderParams[1],
) {
const option = this.getOptions();
try {
const option = this.getOptions();

const result = transform(code, {
filename: this.resourcePath,
root: process.cwd(),
packageName: option.packageName,
variants: option.variants,
inject: option.inject,
});

if (result.type === "Ok") {
if (result.css) {
const importCode = createCSSImportCode(result.css, {
context: this,
cssOutDir: option.cssOutDir,
});

if (option.configDependencies) {
for (const dependency of option.configDependencies) {
this.addDependency(dependency);
}
}

this.callback(undefined, `${result.code}\n${importCode}`);
} else {
this.callback(undefined, code, map);
Expand Down
Loading

0 comments on commit 2f59bf8

Please sign in to comment.