UNPKG

rollup-plugin-react-scoped-css

Version:

A rollup plugin designed to allow scoped css to be run in react (Compatible with vite and rollup)

107 lines (106 loc) 4.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.reactScopedCssPlugin = reactScopedCssPlugin; const path_1 = require("path"); const js_xxhash_1 = require("js-xxhash"); const pluginutils_1 = require("@rollup/pluginutils"); const escodegen_1 = require("escodegen"); const ast_program_1 = require("./ast-program"); const scope_css_1 = require("./css/scope-css"); const getImportDeclarationsValue_1 = require("./utils/getImportDeclarationsValue"); const getFilenameFromPath = (filePath) => { const parts = filePath.split("/"); return parts[parts.length - 1].split("?")[0]; }; const getHashFromPath = (filePath) => { const search = "?scope="; const hash = filePath.slice(filePath.indexOf(search) + search.length); return hash; }; const generateHash = (input, seed = 0) => { const hashNum = (0, js_xxhash_1.xxHash32)(Buffer.from(input, "utf8"), seed); return hashNum.toString(16); }; function reactScopedCssPlugin(optionsIn = {}) { const options = { scopeStyleByDefault: false, scopedStyleSuffix: "scoped", globalStyleSuffix: "global", styleFileExtensions: ["css", "scss", "sass", "less"], jsxFileExtensions: ["jsx", "tsx"], ...optionsIn, }; const { exclude, globalStyleSuffix, hashPrefix, jsxFileExtensions, include, scopeStyleByDefault, scopedStyleSuffix, styleFileExtensions, } = options; if (!styleFileExtensions || !styleFileExtensions.length) { throw new Error("You need to provide at least one style file extension"); } if (!jsxFileExtensions || !jsxFileExtensions.length) { throw new Error("You need to provide at least one jsx file extension"); } const filter = (0, pluginutils_1.createFilter)(include, exclude); const scopedCssRegex = new RegExp(!scopeStyleByDefault ? `([^\.]+\.${scopedStyleSuffix}\.(${styleFileExtensions.join("|")}))$` : `([^\.]+\.(${styleFileExtensions.join("|")}))$`); const globalCssRegex = new RegExp(`\.${globalStyleSuffix}\.(${styleFileExtensions.join("|")})$`); const jsxRegex = new RegExp(`\.(${jsxFileExtensions.join("|")})$`); return [ { name: "rollup-plugin-react-scoped-css:pre", resolveId(source, importer) { if (!importer) { return; } if (scopedCssRegex.test(source) && jsxRegex.test(importer)) { if (scopeStyleByDefault && globalCssRegex.test(source)) { return; } const importerHash = generateHash(importer); const url = (0, path_1.resolve)((0, path_1.dirname)(importer), `${source}?scope=${importerHash}`); return url; } }, enforce: "pre", }, { name: "rollup-plugin-react-scoped-css:post", transform(code, id) { if (!filter(id) || id.includes("node_modules")) { return; } if (jsxRegex.test(id)) { const rootNode = this.parse(code); const imports = (0, getImportDeclarationsValue_1.getImportDeclarationsValue)(rootNode); const shouldScope = !!imports?.some((match) => { if (scopeStyleByDefault) { return scopedCssRegex.test(match) && !globalCssRegex.test(match); } else { return scopedCssRegex.test(match); } }); if (shouldScope) { const importerHash = generateHash(id); const scopedAttr = hashPrefix ? `data-${hashPrefix}-${importerHash}` : `data-${importerHash}`; const newAst = (0, ast_program_1.addHashAttributesToJsxTagsAst)(rootNode, scopedAttr); const newCode = (0, escodegen_1.generate)(newAst); return newCode; } } else { if (scopedCssRegex.test(getFilenameFromPath(id))) { if (scopeStyleByDefault && globalCssRegex.test(id)) { return; } const importerHash = getHashFromPath(id); const scopedAttr = options.hashPrefix ? `data-${options.hashPrefix}-${importerHash}` : `data-${importerHash}`; return (0, scope_css_1.scopeCss)(code, getFilenameFromPath(id), scopedAttr); } } }, }, ]; }