Rework assets loading to fix splitting CSS chunks
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
// Copyright 2023, 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -40,6 +40,7 @@ pub struct ManifestEntry {
|
||||
|
||||
imports: Option<Vec<Utf8PathBuf>>,
|
||||
|
||||
#[allow(dead_code)]
|
||||
dynamic_imports: Option<Vec<Utf8PathBuf>>,
|
||||
|
||||
integrity: Option<String>,
|
||||
@@ -191,35 +192,24 @@ impl<'a> Asset<'a> {
|
||||
impl Manifest {
|
||||
/// Find all assets which should be loaded for a given entrypoint
|
||||
///
|
||||
/// Returns the main asset and all the assets it imports
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the entrypoint is invalid for this manifest
|
||||
pub fn assets_for<'a>(
|
||||
pub fn find_assets<'a>(
|
||||
&'a self,
|
||||
entrypoint: &'a Utf8Path,
|
||||
) -> Result<BTreeSet<Asset<'a>>, InvalidManifest<'a>> {
|
||||
) -> Result<(Asset<'a>, BTreeSet<Asset<'a>>), InvalidManifest<'a>> {
|
||||
let entry = self.lookup_by_name(entrypoint)?;
|
||||
let main_asset = Asset::new(entry)?;
|
||||
entry
|
||||
.css
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|name| self.lookup_by_file(name).and_then(Asset::new))
|
||||
.chain(std::iter::once(Ok(main_asset)))
|
||||
.collect()
|
||||
}
|
||||
let mut entries = BTreeSet::new();
|
||||
let main_asset = self.find_imported_chunks(entry, &mut entries)?;
|
||||
|
||||
/// Find all assets which should be preloaded for a given entrypoint
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the entrypoint is invalid for this manifest
|
||||
pub fn preload_for<'a>(
|
||||
&'a self,
|
||||
entrypoint: &'a Utf8Path,
|
||||
) -> Result<BTreeSet<Asset<'a>>, InvalidManifest<'a>> {
|
||||
let entry = self.lookup_by_name(entrypoint)?;
|
||||
self.find_preload(entry)
|
||||
// Remove the main asset from the set of imported entries. We had it mainly to
|
||||
// deduplicate the list of assets, but we don't want to include it twice
|
||||
entries.remove(&main_asset);
|
||||
|
||||
Ok((main_asset, entries))
|
||||
}
|
||||
|
||||
/// Lookup an entry in the manifest by its original name
|
||||
@@ -243,41 +233,38 @@ impl Manifest {
|
||||
.ok_or(InvalidManifest::CantFindAssetByFile { file })
|
||||
}
|
||||
|
||||
/// Recursively find all the assets that should be preloaded
|
||||
fn find_preload<'a>(
|
||||
&'a self,
|
||||
entry: &'a ManifestEntry,
|
||||
) -> Result<BTreeSet<Asset<'a>>, InvalidManifest<'a>> {
|
||||
let mut entries = BTreeSet::new();
|
||||
self.find_preload_rec(entry, &mut entries)?;
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
fn find_preload_rec<'a>(
|
||||
fn find_imported_chunks<'a>(
|
||||
&'a self,
|
||||
current_entry: &'a ManifestEntry,
|
||||
entries: &mut BTreeSet<Asset<'a>>,
|
||||
) -> Result<(), InvalidManifest<'a>> {
|
||||
) -> Result<Asset, InvalidManifest<'a>> {
|
||||
let asset = Asset::new(current_entry)?;
|
||||
let inserted = entries.insert(asset);
|
||||
|
||||
// If we inserted the entry, we need to find its dependencies
|
||||
if inserted {
|
||||
let css = current_entry.css.iter().flatten();
|
||||
let assets = current_entry.assets.iter().flatten();
|
||||
for name in css.chain(assets) {
|
||||
let entry = self.lookup_by_file(name)?;
|
||||
self.find_preload_rec(entry, entries)?;
|
||||
if let Some(css) = ¤t_entry.css {
|
||||
for file in css {
|
||||
let entry = self.lookup_by_file(file)?;
|
||||
self.find_imported_chunks(entry, entries)?;
|
||||
}
|
||||
}
|
||||
|
||||
let dynamic_imports = current_entry.dynamic_imports.iter().flatten();
|
||||
let imports = current_entry.imports.iter().flatten();
|
||||
for import in dynamic_imports.chain(imports) {
|
||||
let entry = self.lookup_by_name(import)?;
|
||||
self.find_preload_rec(entry, entries)?;
|
||||
if let Some(assets) = ¤t_entry.assets {
|
||||
for file in assets {
|
||||
let entry = self.lookup_by_file(file)?;
|
||||
self.find_imported_chunks(entry, entries)?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(imports) = ¤t_entry.imports {
|
||||
for import in imports {
|
||||
let entry = self.lookup_by_name(import)?;
|
||||
self.find_imported_chunks(entry, entries)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(asset)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
//! Additional functions, tests and filters used in templates
|
||||
|
||||
use std::{
|
||||
collections::{BTreeSet, HashMap},
|
||||
collections::HashMap,
|
||||
fmt::Formatter,
|
||||
str::FromStr,
|
||||
sync::{atomic::AtomicUsize, Arc},
|
||||
@@ -441,41 +441,26 @@ impl std::fmt::Display for IncludeAsset {
|
||||
|
||||
impl Object for IncludeAsset {
|
||||
fn call(self: &Arc<Self>, _state: &State, args: &[Value]) -> Result<Value, Error> {
|
||||
let (path, kwargs): (&str, Kwargs) = from_args(args)?;
|
||||
|
||||
let preload = kwargs.get("preload").unwrap_or(false);
|
||||
kwargs.assert_all_used()?;
|
||||
let (path,): (&str,) = from_args(args)?;
|
||||
|
||||
let path: &Utf8Path = path.into();
|
||||
|
||||
let assets = self.vite_manifest.assets_for(path).map_err(|_e| {
|
||||
let (main, imported) = self.vite_manifest.find_assets(path).map_err(|_e| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidOperation,
|
||||
"Invalid assets manifest while calling function `include_asset`",
|
||||
)
|
||||
})?;
|
||||
|
||||
let preloads = if preload {
|
||||
self.vite_manifest.preload_for(path).map_err(|_e| {
|
||||
Error::new(
|
||||
ErrorKind::InvalidOperation,
|
||||
"Invalid assets manifest while calling function `include_asset`",
|
||||
)
|
||||
})?
|
||||
} else {
|
||||
BTreeSet::new()
|
||||
};
|
||||
|
||||
let preloads = preloads
|
||||
.iter()
|
||||
// Only preload scripts and stylesheets for now
|
||||
.filter(|asset| asset.is_script() || asset.is_stylesheet())
|
||||
.map(|asset| asset.preload_tag(self.url_builder.assets_base().into()));
|
||||
|
||||
let assets = assets
|
||||
.iter()
|
||||
let assets = std::iter::once(main)
|
||||
.chain(imported.iter().filter(|a| a.is_stylesheet()).copied())
|
||||
.filter_map(|asset| asset.include_tag(self.url_builder.assets_base().into()));
|
||||
|
||||
let preloads = imported
|
||||
.iter()
|
||||
.filter(|a| a.is_script())
|
||||
.map(|asset| asset.preload_tag(self.url_builder.assets_base().into()));
|
||||
|
||||
let tags: Vec<String> = preloads.chain(assets).collect();
|
||||
|
||||
Ok(Value::from_safe_string(tags.join("\n")))
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
import { ArgTypes, Decorator, Parameters, Preview } from "@storybook/react";
|
||||
import { useLayoutEffect } from "react";
|
||||
|
||||
import "../src/main.css";
|
||||
import "../src/shared.css";
|
||||
import i18n from "../src/i18n";
|
||||
|
||||
import localazyMetadata from "./locales";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2022-2024 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -26,19 +26,6 @@ limitations under the License.
|
||||
window.APP_CONFIG = JSON.parse(
|
||||
'{"root": "/account/", "graphqlEndpoint": "/graphql"}',
|
||||
);
|
||||
(function () {
|
||||
const query = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
function handleChange(list) {
|
||||
if (list.matches) {
|
||||
document.documentElement.classList.add("cpd-theme-dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("cpd-theme-dark");
|
||||
}
|
||||
}
|
||||
|
||||
query.addEventListener("change", handleChange);
|
||||
handleChange(query);
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import config from "./config";
|
||||
import { client } from "./graphql";
|
||||
import i18n from "./i18n";
|
||||
import { routeTree } from "./routeTree.gen";
|
||||
import "./main.css";
|
||||
import "./shared.css";
|
||||
|
||||
// Create a new router instance
|
||||
const router = createRouter({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
/* Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,15 +13,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@import url("@fontsource/inter/400.css");
|
||||
@import url("@fontsource/inter/500.css");
|
||||
@import url("@fontsource/inter/600.css");
|
||||
@import url("@fontsource/inter/700.css");
|
||||
@import url("@fontsource/inconsolata/400.css");
|
||||
@import url("@fontsource/inconsolata/700.css");
|
||||
@import url("@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css");
|
||||
@import url("@vector-im/compound-web/dist/style.css");
|
||||
|
||||
@import url("./styles/cpd-button.css");
|
||||
@import url("./styles/cpd-form.css");
|
||||
@import url("./styles/cpd-link.css");
|
||||
@@ -35,12 +26,6 @@
|
||||
@import url("./components/Footer/Footer.module.css");
|
||||
@import url("./components/PageHeading/PageHeading.module.css");
|
||||
|
||||
@config "../tailwind.templates.config.cjs";
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.cpd-text-body-lg-regular {
|
||||
font: var(--cpd-font-body-lg-regular);
|
||||
letter-spacing: var(--cpd-font-letter-spacing-body-lg);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -18,8 +18,7 @@
|
||||
|
||||
module.exports = {
|
||||
mode: "jit",
|
||||
content: ["./src/**/*.tsx", "./index.html"],
|
||||
darkMode: ["class", ".cpd-theme-dark"],
|
||||
content: ["./src/**/*.tsx", "./index.html", "../templates/**/*.html"],
|
||||
theme: {
|
||||
colors: {
|
||||
white: "#FFFFFF",
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// @ts-check
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
|
||||
const base = require("./tailwind.config.cjs");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
...base,
|
||||
content: ["../templates/**/*.html"],
|
||||
darkMode: "media",
|
||||
};
|
||||
@@ -59,14 +59,12 @@ export default defineConfig((env) => ({
|
||||
sourcemap: true,
|
||||
modulePreload: false,
|
||||
target: browserslistToEsbuild(),
|
||||
|
||||
// We don't exactly handle CSS code splitting well if we're lazy loading components.
|
||||
// We disabled lazy loading for now, but we should fix this at some point.
|
||||
cssCodeSplit: true,
|
||||
|
||||
rollupOptions: {
|
||||
input: [
|
||||
resolve(__dirname, "src/main.tsx"),
|
||||
resolve(__dirname, "src/shared.css"),
|
||||
resolve(__dirname, "src/templates.css"),
|
||||
],
|
||||
},
|
||||
|
||||
@@ -23,27 +23,14 @@ limitations under the License.
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{{ _("app.name") }}</title>
|
||||
{% set config = {
|
||||
'graphqlEndpoint': app_config.graphqlEndpoint,
|
||||
'root': app_config.root,
|
||||
} -%}
|
||||
<script>
|
||||
{% set config = {
|
||||
'graphqlEndpoint': app_config.graphqlEndpoint,
|
||||
'root': app_config.root,
|
||||
} -%}
|
||||
window.APP_CONFIG = JSON.parse("{{ config | tojson | add_slashes | safe }}");
|
||||
(function () {
|
||||
const query = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
function handleChange(list) {
|
||||
if (list.matches) {
|
||||
document.documentElement.classList.add("cpd-theme-dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("cpd-theme-dark");
|
||||
}
|
||||
}
|
||||
|
||||
query.addEventListener("change", handleChange);
|
||||
handleChange(query);
|
||||
})();
|
||||
</script>
|
||||
{{ include_asset('src/main.tsx', preload=true) | indent(4) | safe }}
|
||||
{{ include_asset('src/main.tsx') | indent(4) | safe }}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -31,7 +31,8 @@ limitations under the License.
|
||||
<meta charset="utf-8">
|
||||
<title>{% block title %}{{ _("app.name") }}{% endblock title %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
{{ include_asset('src/templates.css', preload=true) | indent(4) | safe }}
|
||||
{{ include_asset('src/shared.css') | indent(4) | safe }}
|
||||
{{ include_asset('src/templates.css') | indent(4) | safe }}
|
||||
{{ captcha.head() }}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user