UNPKG

@lcap/builder

Version:
277 lines (273 loc) 12.5 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const path_1 = __importDefault(require("path")); const fast_glob_1 = __importDefault(require("fast-glob")); const fs_extra_1 = __importDefault(require("fs-extra")); const vite_1 = require("vite"); const lodash_1 = require("lodash"); const virtual_file_names_1 = require("../constants/virtual-file-names"); const input_paths_1 = require("../constants/input-paths"); const defaultOptions = { themeVarCssPath: './src/theme/vars.css', themeComponentFolder: './src/theme/components', }; function genVarCssCode(_a) { var { themeVarCssPath, themeComponentFolder: componentFolder, findThemeType } = _a, reset = __rest(_a, ["themeVarCssPath", "themeComponentFolder", "findThemeType"]); const cssVars = []; if (themeVarCssPath) { cssVars.push(themeVarCssPath); } const varsPath = findThemeType === 'component' ? '*/theme/vars.css' : '*/vars.css'; const varFiles = fast_glob_1.default.sync(varsPath, { cwd: componentFolder, absolute: true }); if (varFiles.length > 0) { cssVars.push(...varFiles); } if (reset.dependencies && reset.dependencies.length > 0) { reset.dependencies.forEach(({ rootPath }) => { const depVarFiles = fast_glob_1.default.sync('*/vars.css', { cwd: path_1.default.resolve(rootPath, './src/theme/components'), absolute: true }); if (depVarFiles.length > 0) { cssVars.push(...depVarFiles); } }); } const code = cssVars.map((filePath) => `@import '${(0, vite_1.normalizePath)(filePath)}';`).join('\n'); return code; } function genComponentStoriesCode({ themeComponentFolder: componentFolder = '', framework, findThemeType, dependencies, }) { const imports = [ `import createComponentPreview from '${(0, vite_1.normalizePath)(path_1.default.resolve(__dirname, `../../input/${framework}/createComponentPreview`))}';`, ]; const stories = ['const stories = [']; const previewFilePath = findThemeType === 'component' ? '*/theme/index.{tsx,ts,jsx,js,vue}' : '*/index.{tsx,ts,jsx,js,vue}'; const previewFiles = fast_glob_1.default.sync(previewFilePath, { cwd: componentFolder }); previewFiles.forEach((previewPath) => { const filePath = path_1.default.resolve(componentFolder, previewPath); const compName = previewPath.substring(0, previewPath.indexOf('/')); const varName = (0, lodash_1.upperFirst)((0, lodash_1.camelCase)(compName)); const name = framework && framework.startsWith('vue') ? (0, lodash_1.kebabCase)(varName) : varName; imports.push(`import ${varName} from '${(0, vite_1.normalizePath)(filePath)}';`); stories.push(`{ demo: ${varName}, name: '${name}' },`); }); if (dependencies && dependencies.length > 0) { dependencies.forEach(({ rootPath }) => { const themeCompRootPath = path_1.default.resolve(rootPath, './src/theme/components'); const files = fast_glob_1.default.sync(previewFilePath, { cwd: themeCompRootPath }); files.forEach((previewPath) => { const filePath = path_1.default.resolve(themeCompRootPath, previewPath); const compName = previewPath.substring(0, previewPath.indexOf('/')); const varName = (0, lodash_1.upperFirst)((0, lodash_1.camelCase)(compName)); const name = framework && framework.startsWith('vue') ? (0, lodash_1.kebabCase)(varName) : varName; imports.push(`import ${varName} from '${(0, vite_1.normalizePath)(filePath)}';`); stories.push(`{ demo: ${varName}, name: '${name}' },`); }); }); } stories.push('];'); return [ imports.join('\n'), stories.join('\n'), 'export const demos = stories;', 'export default createComponentPreview(stories);', ].join('\n\n'); } function genThemePagePreviewMapCode({ themeComponentFolder: componentFolder = '', previewPages = [] }) { const importCodes = []; const exportCodes = []; previewPages.forEach(({ name }) => { const importPath = (0, vite_1.normalizePath)(path_1.default.resolve(componentFolder, `../previews/${name}`)); importCodes.push(`import ${name} from '${importPath}';`); exportCodes.push(` ${name},`); }); exportCodes.unshift('export default {'); exportCodes.push('};'); return [ importCodes.join('\n'), exportCodes.join('\n'), ].join('\n\n'); } function genThemeEntryCode({ framework, type, pkg }) { if (framework === 'vue2') { return [ 'import Vue from \'vue\';', `import App from '${(0, vite_1.normalizePath)(path_1.default.resolve(__dirname, '../../input/vue2/App'))}';`, 'Vue.config.productionTip = false;', 'const app = new Vue({ ...App });', 'window.Vue = Vue;', 'app.$mount("#app");', ].join('\n'); } if (framework === 'vue3') { const hasLcapUI = type === 'extension' && pkg && pkg.lcap && pkg.lcap['lcap-ui']; return [ 'import { createApp } from \'vue\';', 'import * as Library from "@/index"', `import App from '${(0, vite_1.normalizePath)(path_1.default.resolve(__dirname, '../../input/vue3/App'))}';`, 'const app = createApp(App);', 'window.__app = app;', ...(hasLcapUI ? [ 'import "virtual-lcap:lcap-ui.css";', 'import * as LcapUI from "virtual-lcap:lcap-ui";', 'app.use(LcapUI);', ] : []), 'app.use(Library);', 'app.mount("#app");', ].join('\n'); } const importCodes = [ 'import React from \'react\';', 'import ReactDOM from \'react-dom/client\'', `import App from '${(0, vite_1.normalizePath)(path_1.default.resolve(__dirname, '../../input/react/App'))}';`, ]; const bodyCodes = [ 'const root = ReactDOM.createRoot(document.getElementById("app"));', 'root.render(React.createElement(App, {}))', ]; return [ importCodes.join('\n'), bodyCodes.join('\n'), ].join('\n\n'); } const InstallLibraryCode = `function installLibrary(Vue, Components) { const caseRE = /^[A-Z]/; const blackList = ['directives', 'filters', 'utils', 'mixins', 'blocks', 'vendors', 'install', 'default']; // 组件之间有依赖,有 install 的必须先安装 Object.keys(Components).forEach((key) => { if (!caseRE.test(key)) { // 如果为大写则是组件 if (!blackList.includes(key)) console.error('不允许组件名首字母小写', key, Components[key]); return; } const Component = Components[key]; if (Component.install) { Vue.component(key, Component); Component.install(Vue, key); } }); Object.keys(Components).forEach((key) => { if (!caseRE.test(key)) { // 如果为大写则是组件 if (!blackList.includes(key)) console.error('不允许组件名首字母小写', key, Components[key]); return; } const Component = Components[key]; Vue.component(key, Component); if (!Component.install) { Vue.component(key, Component); } }); }`; function genDefaultPreviewCode({ framework, type, pkg, }) { const isExtension = type === 'extension'; const codes = [ `export { default as ComponentWrap } from '${(0, vite_1.normalizePath)(path_1.default.resolve(__dirname, `../../input/${framework}/component-preview`))}'`, 'export const renderAppPreview = (app) => app;', ]; if (framework && framework === 'vue2') { const importCodes = [ 'import Vue from "vue";', 'import * as Library from "@/index"', ]; if (isExtension && pkg && pkg.lcap && pkg.lcap['lcap-ui']) { importCodes.push('import "virtual-lcap:lcap-ui.css";'); importCodes.push('import * as LcapUI from "virtual-lcap:lcap-ui";'); importCodes.push('Vue.use(LcapUI);'); } importCodes.push(isExtension ? [InstallLibraryCode, 'installLibrary(Vue, Library);'].join('\n') : 'Vue.use(Library);'); codes.unshift(''); codes.unshift(importCodes.join('\n')); } return codes.join('\n'); } function genThemePagePreviewWrapCode(options) { const { rootPath = '', themePreviewEntry } = options; if (themePreviewEntry) { let filePath = ''; const index = [ '.js', '.jsx', '.tsx', ].findIndex((ext) => { filePath = path_1.default.resolve(rootPath, themePreviewEntry, `../index${ext}`); if (fs_extra_1.default.existsSync(filePath)) { return true; } return false; }); if (index !== -1) { return [ `export { renderAppPreview, ComponentWrap } from '${(0, vite_1.normalizePath)(filePath)}';`, ].join('\n'); } } return genDefaultPreviewCode(options); } exports.default = (options = {}) => { const cwd = process.cwd(); let themeId; const themeVarCssPath = options.themeVarCssPath ? path_1.default.resolve(cwd, options.themeVarCssPath) : ''; const componentFolder = path_1.default.resolve(cwd, options.themeComponentFolder || defaultOptions.themeComponentFolder); const genOptions = Object.assign(Object.assign({}, options), { themeVarCssPath, themeComponentFolder: componentFolder, rootPath: cwd, pkg: fs_extra_1.default.readJSONSync(path_1.default.resolve(cwd, 'package.json')) }); return { name: 'vite:lcap-code-gen', // 必须的,将会在 warning 和 error 中显示 enforce: 'pre', configResolved(config) { themeId = `${config.root}/index.html`; }, resolveId(source) { if (source === virtual_file_names_1.virtualThemeCSSFileId) { return virtual_file_names_1.virtualThemeCSSFileId; } if (source === virtual_file_names_1.virtualThemeComponentStoriesFileId) { return virtual_file_names_1.virtualThemeComponentStoriesFileId; } if (source === virtual_file_names_1.virtualThemePagePreviewFileId) { return virtual_file_names_1.virtualThemePagePreviewFileId; } if (source === virtual_file_names_1.virtualThemeEntryFileId) { return virtual_file_names_1.virtualThemeEntryFileId; } if (source === virtual_file_names_1.virtualThemePreviewWrapFileId) { return virtual_file_names_1.virtualThemePreviewWrapFileId; } if (source === input_paths_1.themePath) { return themeId; } return undefined; }, load: (id) => { if (id === virtual_file_names_1.virtualThemeCSSFileId) { return genVarCssCode(genOptions); } if (id === virtual_file_names_1.virtualThemeComponentStoriesFileId) { return genComponentStoriesCode(genOptions); } if (id === virtual_file_names_1.virtualThemePagePreviewFileId) { return genThemePagePreviewMapCode(genOptions); } if (id === virtual_file_names_1.virtualThemePreviewWrapFileId) { return genThemePagePreviewWrapCode(genOptions); } if (id === virtual_file_names_1.virtualThemeEntryFileId) { return genThemeEntryCode(genOptions); } if (id === themeId) { return fs_extra_1.default.readFileSync(input_paths_1.themePath, 'utf-8'); } return undefined; }, }; };