UNPKG

rollup-plugin-tsx-scoped-css

Version:
134 lines (133 loc) 5.36 kB
var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "@vue/component-compiler-utils", "fs", "md5", "path", "ts-morph"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const component_compiler_utils_1 = require("@vue/component-compiler-utils"); const fs_1 = __importDefault(require("fs")); const md5_1 = __importDefault(require("md5")); const path_1 = __importDefault(require("path")); const ts_morph_1 = require("ts-morph"); const project = new ts_morph_1.Project({ tsConfigFilePath: findTsConfig(), }); const hash_cache = {}; function default_1(raw_options = {}) { const options = { isScopedCssFile, ...raw_options.isScopedCssFile, }; return { name: 'rollup-plugin-tsx-scoped-css', enforce: 'pre', transform(code, filepath) { // 处理 css 文件 if (options.isScopedCssFile(filepath)) return handleCssFile(code, filepath); // 处理 jsx/tsx 文件 if (filepath.endsWith('sx')) return handleTsxFile(code, filepath, options); return code; }, }; } exports.default = default_1; function findTsConfig() { let root = process.cwd(); do { const config_filepath = path_1.default.join(root, 'tsconfig.json'); if (fs_1.default.existsSync(config_filepath)) { return config_filepath; } root = path_1.default.normalize(path_1.default.join(root, '..')); } while (root !== '/'); } function handleTsxFile(code, filepath, options) { const file = project.addSourceFileAtPath(filepath); const imports = file.getImportDeclarations().filter(_import => { return options.isScopedCssFile(_import.getModuleSpecifierValue()); }); // 如果没有 import scoped css 文件,则不需要处理 if (imports.length === 0) { return code; } const hashes = []; imports.forEach(_import => { const module_path = _import.getModuleSpecifierValue(); let real_path = ''; // 没有使用 paths if (module_path.startsWith('.')) { real_path = path_1.default.resolve(path_1.default.join(path_1.default.dirname(filepath), module_path)); } else { const tsconfig = project.getCompilerOptions(); if (tsconfig.paths) { const aliases = { ...tsconfig.paths }; Object.keys(aliases).forEach(source => { for (let target of aliases[source]) { target = path_1.default.resolve(path_1.default.join(tsconfig.baseUrl, target)); real_path = module_path.replace(source.replace('*', ''), target.replace('*', '')); if (fs_1.default.existsSync(real_path)) { break; } } }); } } if (fs_1.default.existsSync(real_path)) { const hash = getFilepathHash(real_path); hashes.push(hash); } }); const jsx_elements = [ ...file.getDescendantsOfKind(ts_morph_1.SyntaxKind.JsxOpeningElement), ...file.getDescendantsOfKind(ts_morph_1.SyntaxKind.JsxSelfClosingElement), ]; // 遍历每一个 jsx 元素 const hash_attrs = hashes.map(hash => `data-v-${hash}`); jsx_elements .filter((jsx_element => jsx_element.getFullText().trim() !== '<React.Fragment>')) .forEach((jsx_element) => { hash_attrs.forEach(hash => { jsx_element.addAttribute({ name: hash, initializer: '""' }); }); }); const result_code = file.getFullText(); project.removeSourceFile(file); return result_code; } function handleCssFile(source, filepath) { const hash = getFilepathHash(filepath); const { code, errors } = component_compiler_utils_1.compileStyle({ source, filename: filepath, id: `data-v-${hash}`, scoped: true, trim: true, }); if (errors.length) { console.error(errors[0]); } return code; } function isScopedCssFile(filepath) { return /\.scoped\.(c|le|sa|sc)ss$/.test(filepath); } function getFilepathHash(filepath) { filepath = path_1.default.resolve(filepath); let hash = hash_cache[filepath]; if (!hash) { hash_cache[filepath] = hash = md5_1.default(filepath).substr(0, 8); } return hash; } });