Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Commit 733cd91

Browse files
committed
fix: fix remote css importing
1 parent 488b27e commit 733cd91

File tree

7 files changed

+92
-41
lines changed

7 files changed

+92
-41
lines changed

compiler/src/resolve.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,6 @@ impl Resolver {
218218
} else {
219219
if url.starts_with("/") {
220220
url.into()
221-
} else if url.starts_with("@/") {
222-
url.trim_start_matches("@").into()
223-
} else if url.starts_with("~/") {
224-
url.trim_start_matches("~").into()
225221
} else {
226222
let mut buf = PathBuf::from(self.specifier.as_str());
227223
buf.pop();
@@ -337,21 +333,22 @@ impl Resolver {
337333
resolved_path.set_file_name(filename);
338334
}
339335
_ => {
336+
let mut filename = resolved_path
337+
.file_name()
338+
.unwrap()
339+
.to_str()
340+
.unwrap()
341+
.to_owned();
342+
if self.bundle_mode && !is_dynamic {
343+
filename.push_str(".bundling");
344+
}
345+
filename.push_str(".js");
340346
if !is_remote && !self.specifier_is_remote {
341-
let mut filename = resolved_path
342-
.file_name()
343-
.unwrap()
344-
.to_str()
345-
.unwrap()
346-
.to_owned();
347-
if self.bundle_mode && !is_dynamic {
348-
filename.push_str(".bundling");
349-
}
350-
filename.push_str(".js#");
347+
filename.push('#');
351348
filename.push_str(fixed_url.as_str());
352349
filename.push_str("@000000");
353-
resolved_path.set_file_name(filename);
354350
}
351+
resolved_path.set_file_name(filename);
355352
}
356353
},
357354
None => {}
@@ -538,6 +535,13 @@ mod tests {
538535
"/styles/app.css".into()
539536
)
540537
);
538+
assert_eq!(
539+
resolver.resolve("https://esm.sh/tailwindcss/dist/tailwind.min.css", false),
540+
(
541+
"../-/esm.sh/tailwindcss/dist/tailwind.min.css.js".into(),
542+
"https://esm.sh/tailwindcss/dist/tailwind.min.css".into()
543+
)
544+
);
541545
assert_eq!(
542546
resolver.resolve("@/components/logo.tsx", false),
543547
(

compiler/src/resolve_fold.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,7 @@ mod tests {
700700
return (
701701
<>
702702
<head>
703+
<link rel="stylesheet" href="https://esm.sh/tailwindcss/dist/tailwind.min.css" />
703704
<link rel="stylesheet" href="../style/index.css" />
704705
</head>
705706
<Logo />
@@ -746,6 +747,8 @@ mod tests {
746747
assert!(code.contains(
747748
"import __ALEPH_Stylelink from \"../-/deno.land/x/aleph/framework/react/stylelink.bundling.js\""
748749
));
750+
assert!(code.contains("import \"../-/esm.sh/tailwindcss/dist/tailwind.min.css.bundling.js\""));
751+
assert!(code.contains("import \"../style/index.css.bundling.js#/style/index.css@000000\""));
749752
assert!(code.contains("export const $$star_0 = __ALEPH.pack[\"https://esm.sh/react\"]"));
750753
assert!(code.contains("export const ReactDom = __ALEPH.pack[\"https://esm.sh/react-dom\"]"));
751754
assert!(code.contains("export const { render } = __ALEPH.pack[\"https://esm.sh/react-dom\"]"));

framework/core/style.ts

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,67 @@
11
import util from '../../shared/util.ts'
22

3+
export const clientStyles = new Map<string, string>()
34
export const serverStyles = new Map<string, string>()
4-
export const recoverStyles = new Map<string, string>()
55

6-
export function removeCSS(id: string, recoverable?: boolean) {
6+
export function removeCSS(url: string, recoverable?: boolean) {
77
const { document } = window as any
88
Array.from(document.head.children).forEach((el: any) => {
9-
if (el.getAttribute('data-module-id') === id) {
9+
if (el.getAttribute('data-module-id') === url) {
1010
if (recoverable) {
11-
recoverStyles.set(id, el.innerHTML)
11+
const tag = el.tagName.toLowerCase()
12+
if (tag === 'style') {
13+
clientStyles.set(url, el.innerHTML)
14+
} else if (tag === 'link') {
15+
clientStyles.set(url, '')
16+
}
1217
}
1318
document.head.removeChild(el)
1419
}
1520
})
1621
}
1722

18-
export function recoverCSS(id: string) {
19-
if (recoverStyles.has(id)) {
20-
applyCSS(id, recoverStyles.get(id)!)
23+
export function recoverCSS(url: string) {
24+
if (clientStyles.has(url)) {
25+
const css = clientStyles.get(url)!
26+
if (css === '' && util.isLikelyHttpURL(url)) {
27+
applyCSS(url)
28+
} else {
29+
applyCSS(url, css)
30+
}
2131
}
2232
}
2333

24-
export function applyCSS(id: string, css: string) {
34+
export function applyCSS(url: string, css?: string) {
2535
if (util.inDeno) {
26-
serverStyles.set(id, css)
36+
serverStyles.set(url, css || '')
2737
} else {
2838
const { document } = window as any
29-
const ssrStyle = Array.from<any>(document.head.children).find((el: any) => {
30-
return el.getAttribute('data-module-id') === id && el.hasAttribute('ssr')
39+
const ssr = Array.from<any>(document.head.children).find((el: any) => {
40+
return el.getAttribute('data-module-id') === url && el.hasAttribute('ssr')
3141
})
32-
if (ssrStyle) {
33-
ssrStyle.removeAttribute('ssr')
42+
if (ssr) {
43+
// apply the css at next time
44+
ssr.removeAttribute('ssr')
3445
} else {
35-
const prevStyleEls = Array.from(document.head.children).filter((el: any) => {
36-
return el.getAttribute('data-module-id') === id
46+
const prevEls = Array.from(document.head.children).filter((el: any) => {
47+
return el.getAttribute('data-module-id') === url
3748
})
38-
const styleEl = document.createElement('style')
39-
styleEl.type = 'text/css'
40-
styleEl.appendChild(document.createTextNode(css))
41-
styleEl.setAttribute('data-module-id', id)
42-
document.head.appendChild(styleEl)
43-
if (prevStyleEls.length > 0) {
44-
prevStyleEls.forEach(el => document.head.removeChild(el))
49+
let el: any
50+
if (css !== undefined) {
51+
el = document.createElement('style')
52+
el.type = 'text/css'
53+
el.appendChild(document.createTextNode(css))
54+
} else if (util.isLikelyHttpURL(url)) {
55+
el = document.createElement('link')
56+
el.rel = 'stylesheet'
57+
el.href = url
58+
} else {
59+
throw new Error('applyCSS: missing css')
60+
}
61+
el.setAttribute('data-module-id', url)
62+
document.head.appendChild(el)
63+
if (prevEls.length > 0) {
64+
prevEls.forEach(el => document.head.removeChild(el))
4565
}
4666
}
4767
}

framework/react/bootstrap.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ export default async function bootstrap(options: BootstrapOptions) {
5151
// remove ssr head elements, set a timmer to avoid the tab title flash
5252
setTimeout(() => {
5353
Array.from(document.head.children).forEach((el: any) => {
54-
if (el.hasAttribute('ssr') && el.tagName.toLowerCase() !== 'style') {
54+
const tag = el.tagName.toLowerCase()
55+
if (
56+
el.hasAttribute('ssr') &&
57+
tag !== 'style' &&
58+
!(tag === 'link' && el.getAttribute('rel') === 'stylesheet')
59+
) {
5560
document.head.removeChild(el)
5661
}
5762
})

framework/react/renderer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,11 @@ export async function render(
139139

140140
// get styles
141141
serverStyles.forEach((css, url) => {
142-
ret.head.push(`<style type="text/css" data-module-id=${JSON.stringify(url)} ssr>${css}</style>`)
142+
if (css) {
143+
ret.head.push(`<style type="text/css" data-module-id=${JSON.stringify(url)} ssr>${css}</style>`)
144+
} else if (util.isLikelyHttpURL(url)) {
145+
ret.head.push(`<link rel="stylesheet" href="${url}" data-module-id=${JSON.stringify(url)} ssr />`)
146+
}
143147
})
144148

145149
defer()

plugins/css.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type { LoaderPlugin } from '../types.ts'
77
const postcssVersion = '8.2.8'
88
const productionOnlyPostcssPlugins = ['autoprefixer']
99
const decoder = new TextDecoder()
10+
const importDecl = 'import { applyCSS } from "https://deno.land/x/aleph/framework/core/style.ts"'
1011

1112
export type AcceptedPlugin = string | [string, any] | Plugin | PluginCreator<any>
1213

@@ -26,7 +27,21 @@ export default (options?: Options): LoaderPlugin => {
2627
type: 'loader',
2728
test: /\.p?css$/i,
2829
acceptHMR: true,
30+
async resolve(url: string) {
31+
if (util.isLikelyHttpURL(url)) {
32+
return Promise.resolve(new Uint8Array())
33+
}
34+
return Deno.readFile(join(Deno.cwd(), url))
35+
},
2936
async transform({ url, content }) {
37+
if (util.isLikelyHttpURL(url)) {
38+
return {
39+
code: [
40+
importDecl,
41+
`applyCSS(${JSON.stringify(url)})`
42+
].join('\n')
43+
}
44+
}
3045
if (isProd === null) {
3146
isProd = Deno.env.get('BUILD_MODE') === 'production'
3247
}
@@ -48,7 +63,7 @@ export default (options?: Options): LoaderPlugin => {
4863
}
4964
return {
5065
code: [
51-
'import { applyCSS } from "https://deno.land/x/aleph/framework/core/style.ts"',
66+
importDecl,
5267
`applyCSS(${JSON.stringify(url)}, ${JSON.stringify(css)})`
5368
].join('\n')
5469
// todo: generate map

server/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ export class Application implements ServerApplication {
507507
}
508508

509509
isHMRable(url: string) {
510-
if (!this.isDev) {
510+
if (!this.isDev || util.isLikelyHttpURL(url)) {
511511
return false
512512
}
513513

0 commit comments

Comments
 (0)