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
JavaScript
;
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);
}
}
},
},
];
}