From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../storybook/.storybook/chrome-styles-loader.js | 145 +++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 browser/components/storybook/.storybook/chrome-styles-loader.js (limited to 'browser/components/storybook/.storybook/chrome-styles-loader.js') diff --git a/browser/components/storybook/.storybook/chrome-styles-loader.js b/browser/components/storybook/.storybook/chrome-styles-loader.js new file mode 100644 index 0000000000..4a66128320 --- /dev/null +++ b/browser/components/storybook/.storybook/chrome-styles-loader.js @@ -0,0 +1,145 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* eslint-env node */ + +/** + * This file contains a webpack loader which rewrites JS source files to use CSS + * imports when running in Storybook. This allows JS files loaded in Storybook to use + * chrome:// URIs when loading external stylesheets without having to worry + * about Storybook being able to find and detect changes to the files. + * + * This loader allows Lit-based custom element code like this to work with + * Storybook: + * + * render() { + * return html` + * + * ... + * `; + * } + * + * By rewriting the source to this: + * + * import moztoggleStyles from "toolkit/content/widgets/moz-toggle/moz-toggle.css"; + * ... + * render() { + * return html` + * + * ... + * `; + * } + * + * It works similarly for vanilla JS custom elements that utilize template + * strings. The following code: + * + * static get markup() { + * return` + * + * `; + * } + * + * Gets rewritten to: + * + * import migrationwizardStyles from "browser/themes/shared/migration/migration-wizard.css"; + * ... + * static get markup() { + * return` + * + * `; + * } + */ + +const path = require("path"); +const projectRoot = path.join(process.cwd(), "../../.."); +const rewriteChromeUri = require("./chrome-uri-utils.js"); + +/** + * Return an array of the unique chrome:// CSS URIs referenced in this file. + * + * @param {string} source - The source file to scan. + * @returns {string[]} Unique list of chrome:// CSS URIs + */ +function getReferencedChromeUris(source) { + const chromeRegex = /chrome:\/\/.*?\.css/g; + const matches = new Set(); + for (let match of source.matchAll(chromeRegex)) { + // Add the full URI to the set of matches. + matches.add(match[0]); + } + return [...matches]; +} + +/** + * Replace references to chrome:// URIs with the relative path on disk from the + * project root. + * + * @this {WebpackLoader} https://webpack.js.org/api/loaders/ + * @param {string} source - The source file to update. + * @returns {string} The updated source. + */ +async function rewriteChromeUris(source) { + const chromeUriToLocalPath = new Map(); + // We're going to rewrite the chrome:// URIs, find all referenced URIs. + let chromeDependencies = getReferencedChromeUris(source); + for (let chromeUri of chromeDependencies) { + let localRelativePath = rewriteChromeUri(chromeUri); + if (localRelativePath) { + localRelativePath = localRelativePath.replaceAll("\\", "/"); + // Store the mapping to a local path for this chrome URI. + chromeUriToLocalPath.set(chromeUri, localRelativePath); + // Tell webpack the file being handled depends on the referenced file. + this.addMissingDependency(path.join(projectRoot, localRelativePath)); + } + } + // Rewrite the source file with mapped chrome:// URIs. + let rewrittenSource = source; + for (let [chromeUri, localPath] of chromeUriToLocalPath.entries()) { + // Generate an import friendly variable name for the default export from + // the CSS file e.g. __chrome_styles_loader__moztoggleStyles. + let cssImport = `__chrome_styles_loader__${path + .basename(localPath, ".css") + .replaceAll("-", "")}Styles`; + + // MozTextLabel is a special case for now since we don't use a template. + if ( + this.resourcePath.endsWith("/moz-label.mjs") || + this.resourcePath.endsWith(".js") + ) { + rewrittenSource = rewrittenSource.replaceAll(`"${chromeUri}"`, cssImport); + } else { + rewrittenSource = rewrittenSource.replaceAll( + chromeUri, + `\$\{${cssImport}\}` + ); + } + + // Add a CSS import statement as the first line in the file. + rewrittenSource = + `import ${cssImport} from "${localPath}";\n` + rewrittenSource; + } + return rewrittenSource; +} + +/** + * The WebpackLoader export. Runs async since apparently that's preferred. + * + * @param {string} source - The source to rewrite. + * @param {Map} sourceMap - Source map data, unused. + * @param {Object} meta - Metadata, unused. + */ +module.exports = async function chromeUriLoader(source) { + // Get a callback to tell webpack when we're done. + const callback = this.async(); + // Rewrite the source async since that appears to be preferred (and will be + // necessary once we support rewriting CSS/SVG/etc). + const newSource = await rewriteChromeUris.call(this, source); + // Give webpack the rewritten content. + callback(null, newSource); +}; -- cgit v1.2.3