@lcap/builder
Version:
lcap builder utils
277 lines (273 loc) • 12.5 kB
JavaScript
;
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;
},
};
};