@moneko/core 3.2.1-beta.1 → 3.2.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1,6 @@
1
- import{CONFIG as e}from"./config.js";let t="";e.normalizeCss&&(t='html,body{margin:0;padding:0;line-height:1.8}input,textarea{caret-color:inherit}h1{margin:0.67em 0;font-size:2em}hr{overflow:visible;block-size:0;box-sizing:content-box}pre{font-size:1em;font-family:monospace}a{text-decoration:none;background-color:transparent;cursor:pointer}abbr[title]{border-block-end:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-size:1em;font-family:monospace}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{inset-block-end:-0.25em}sup{inset-block-start:-0.5em}img{border-style:none}img,button{outline:1px solid transparent}button,input,optgroup,select,textarea{margin:0;font-size:100%;font-family:inherit;line-height:1.15}button,input{overflow:visible}button,select{text-transform:none}button,[type="button"],[type="reset"],[type="submit"]{appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted var(--primary-outline)}fieldset{padding:0.35em 0.75em 0.625em}legend{display:table;padding:0;max-inline-size:100%;white-space:normal;color:inherit;box-sizing:border-box}progress{vertical-align:baseline}textarea{overflow:auto}details{display:block}summary{display:list-item}template,[hidden]{display:none}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{block-size:auto}[type="search"]{appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{appearance:none}::-webkit-file-upload-button{appearance:button;font:inherit}::-webkit-scrollbar{inline-size:5px;block-size:5px}::-webkit-scrollbar-track,::-webkit-scrollbar-thumb{background-color:transparent}:hover::-webkit-scrollbar-thumb{background-color:var(--primary-selection)}::-webkit-scrollbar-thumb:hover{background-color:var(--primary-hover)}::-webkit-scrollbar-thumb:active{background-color:var(--primary-active)}::-webkit-scrollbar-button{display:none}');export default t;
1
+ import { CONFIG } from './config.js';
2
+ let normalizeCss = '';
3
+ if (CONFIG.normalizeCss) {
4
+ normalizeCss = 'html,body{margin:0;padding:0;line-height:1.8}input,textarea{caret-color:inherit}h1{margin:0.67em 0;font-size:2em}hr{overflow:visible;block-size:0;box-sizing:content-box}pre{font-size:1em;font-family:monospace}a{text-decoration:none;background-color:transparent;cursor:pointer}abbr[title]{border-block-end:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-size:1em;font-family:monospace}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{inset-block-end:-0.25em}sup{inset-block-start:-0.5em}img{border-style:none}img,button{outline:1px solid transparent}button,input,optgroup,select,textarea{margin:0;font-size:100%;font-family:inherit;line-height:1.15}button,input{overflow:visible}button,select{text-transform:none}button,[type="button"],[type="reset"],[type="submit"]{appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted var(--primary-outline)}fieldset{padding:0.35em 0.75em 0.625em}legend{display:table;padding:0;max-inline-size:100%;white-space:normal;color:inherit;box-sizing:border-box}progress{vertical-align:baseline}textarea{overflow:auto}details{display:block}summary{display:list-item}template,[hidden]{display:none}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{block-size:auto}[type="search"]{appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{appearance:none}::-webkit-file-upload-button{appearance:button;font:inherit}::-webkit-scrollbar{inline-size:5px;block-size:5px}::-webkit-scrollbar-track,::-webkit-scrollbar-thumb{background-color:transparent}:hover::-webkit-scrollbar-thumb{background-color:var(--primary-selection)}::-webkit-scrollbar-thumb:hover{background-color:var(--primary-hover)}::-webkit-scrollbar-thumb:active{background-color:var(--primary-active)}::-webkit-scrollbar-button{display:none}';
5
+ }
6
+ export default normalizeCss;
package/lib/paths.js CHANGED
@@ -1 +1,21 @@
1
- import{existsSync as e,mkdirSync as o}from"fs";import a from"url";let t=process.cwd(),c=`${t}/node_modules/.cache/.mo`;e(c)||o(c,{recursive:!0});export default{corePath:a.fileURLToPath(new URL(".",import.meta.url)),programPath:t,webpackCachePath:`${t}/node_modules/.temp_cache`,cachePath:c,httpCachePath:`${t}/node_modules/.cache/http`,swcCachePath:`${t}/node_modules/.swc`,defaultConfigPath:`${t}/config/index.ts`,coveragePath:`${t}/coverage/clover.xml`,pagesPath:`${t}/src/pages`,componentsPath:`${t}/components`};
1
+ import { existsSync, mkdirSync } from 'fs';
2
+ import url from 'url';
3
+ const programPath = process.cwd();
4
+ const cachePath = `${programPath}/node_modules/.cache/.mo`;
5
+ if (!existsSync(cachePath)) {
6
+ mkdirSync(cachePath, {
7
+ recursive: true
8
+ });
9
+ }
10
+ export default {
11
+ corePath: url.fileURLToPath(new URL('.', import.meta.url)),
12
+ programPath: programPath,
13
+ webpackCachePath: `${programPath}/node_modules/.temp_cache`,
14
+ cachePath: cachePath,
15
+ httpCachePath: `${programPath}/node_modules/.cache/http`,
16
+ swcCachePath: `${programPath}/node_modules/.swc`,
17
+ defaultConfigPath: `${programPath}/config/index.ts`,
18
+ coveragePath: `${programPath}/coverage/clover.xml`,
19
+ pagesPath: `${programPath}/src/pages`,
20
+ componentsPath: `${programPath}/components`
21
+ };
@@ -1,3 +1,26 @@
1
- function e(...t){/**
2
- * @ts-ignore */// eslint-disable-next-line consistent-this, no-invalid-this, @typescript-eslint/no-this-alias
3
- let o=this,r=t.length,l=Array(r);for(let e=0;e<r;e++)l[e]=t[e];for(;o.firstChild;)o.removeChild(o.firstChild);l.forEach(function(e){"string"==typeof e?o.appendChild(document.createTextNode(e)):o.appendChild(e)})}Element.prototype.replaceChildren||(Element.prototype.replaceChildren=e),ShadowRoot.prototype.replaceChildren||(ShadowRoot.prototype.replaceChildren=e);
1
+ function replaceChildrenPolyfill(...nodes) {
2
+ /**
3
+ * @ts-ignore */ // eslint-disable-next-line consistent-this, no-invalid-this, @typescript-eslint/no-this-alias
4
+ const self = this;
5
+ const l = nodes.length;
6
+ const newChildren = new Array(l);
7
+ for(let k = 0; k < l; k++){
8
+ newChildren[k] = nodes[k];
9
+ }
10
+ while(self.firstChild){
11
+ self.removeChild(self.firstChild);
12
+ }
13
+ newChildren.forEach(function(child) {
14
+ if (typeof child === 'string') {
15
+ self.appendChild(document.createTextNode(child));
16
+ } else {
17
+ self.appendChild(child);
18
+ }
19
+ });
20
+ }
21
+ if (!Element.prototype.replaceChildren) {
22
+ Element.prototype.replaceChildren = replaceChildrenPolyfill;
23
+ }
24
+ if (!ShadowRoot.prototype.replaceChildren) {
25
+ ShadowRoot.prototype.replaceChildren = replaceChildrenPolyfill;
26
+ }
package/lib/polyfills.js CHANGED
@@ -1,3 +1,15 @@
1
- import r from"browserslist";import t from"core-js-compat";import o from"./paths.js";export default function(){return t({// 从项目的根目录自动寻找 browserslistrc 配置
2
- targets:r(void 0,{path:o.programPath,env:process.env.NODE_ENV}).filter(r=>!r.endsWith(" TP")),// 须指定 core-js 前两位具体版本,如 `3.20`,否则 polyfill 会不全
3
- version:"3.32.2"}).list}
1
+ import browserslist from 'browserslist';
2
+ import compat from 'core-js-compat';
3
+ import paths from './paths.js';
4
+ function polyfills() {
5
+ return compat({
6
+ // 从项目的根目录自动寻找 browserslistrc 配置
7
+ targets: browserslist(void 0, {
8
+ path: paths.programPath,
9
+ env: process.env.NODE_ENV
10
+ }).filter((e)=>!e.endsWith(' TP')),
11
+ // 须指定 core-js 前两位具体版本,如 `3.20`,否则 polyfill 会不全
12
+ version: '3.32.2'
13
+ }).list;
14
+ }
15
+ export default polyfills;
@@ -1 +1,6 @@
1
- import{isReact as e}from"./process-env.js";let t="";e&&(t='import { createElement, isValidElement } from "react";import { Outlet } from "react-router-dom";function prefix(e){return e.map(function(e){var n=Object.assign({key:e.path},e);return n.element?isValidElement(n.element)||(n.element=createElement(n.element,n.meta)):n.element=createElement(Outlet,null),Array.isArray(n.children)&&(n.children=prefix(n.children)),n})}export default prefix;');export default t;
1
+ import { isReact } from './process-env.js';
2
+ let prefixRouter = '';
3
+ if (isReact) {
4
+ prefixRouter = 'import { createElement, isValidElement } from "react";import { Outlet } from "react-router-dom";function prefix(e){return e.map(function(e){var n=Object.assign({key:e.path},e);return n.element?isValidElement(n.element)||(n.element=createElement(n.element,n.meta)):n.element=createElement(Outlet,null),Array.isArray(n.children)&&(n.children=prefix(n.children)),n})}export default prefix;';
5
+ }
6
+ export default prefixRouter;
@@ -1,7 +1,38 @@
1
- import{readFileSync as e}from"fs";import o from"./paths.js";import t from"./yarn-argv.js";export const APPTYPE=process.env.APPTYPE;export const FRAMEWORK=process.env.FRAMEWORK;export const isLibrary="library"===APPTYPE;export const isMicro="micro"===APPTYPE;export const isReact="react"===FRAMEWORK;export const isSolid="solid"===FRAMEWORK;export const jsxImportSource={react:"react",solid:"solid-js/h"}[FRAMEWORK];export const createElement={react:"createElement",solid:"createComponent"}[FRAMEWORK];/** 框架名称 */export const FRAMEWORKNAME={react:"react",solid:"solid-js"}[FRAMEWORK];/** 应用名称 */export const PACKAGENAME=process.env.npm_package_name;/** 版本号 */export const PACKAGEVERSION=process.env.npm_package_version;let s=e(`${o.corePath}/../package.json`,{encoding:"utf-8"});/** core 包名 */export const coreName=JSON.parse(s).name;/** 是否为本地开发环境 */export const isDev="development"===process.env.NODE_ENV;/** 附加启动配置名称
1
+ import { readFileSync } from 'fs';
2
+ import paths from './paths.js';
3
+ import yarnArgv from './yarn-argv.js';
4
+ export const APPTYPE = process.env.APPTYPE;
5
+ export const FRAMEWORK = process.env.FRAMEWORK;
6
+ export const isLibrary = APPTYPE === 'library';
7
+ export const isMicro = APPTYPE === 'micro';
8
+ export const isReact = FRAMEWORK === 'react';
9
+ export const isSolid = FRAMEWORK === 'solid';
10
+ export const jsxImportSource = {
11
+ react: 'react',
12
+ solid: 'solid-js/h'
13
+ }[FRAMEWORK];
14
+ export const createElement = {
15
+ react: 'createElement',
16
+ solid: 'createComponent'
17
+ }[FRAMEWORK];
18
+ /** 框架名称 */ export const FRAMEWORKNAME = {
19
+ react: 'react',
20
+ solid: 'solid-js'
21
+ }[FRAMEWORK];
22
+ /** 应用名称 */ export const PACKAGENAME = process.env.npm_package_name;
23
+ /** 版本号 */ export const PACKAGEVERSION = process.env.npm_package_version;
24
+ const pkg = readFileSync(`${paths.corePath}/../package.json`, {
25
+ encoding: 'utf-8'
26
+ });
27
+ /** core 包名 */ export const coreName = JSON.parse(pkg).name;
28
+ /** 是否为本地开发环境 */ export const isDev = process.env.NODE_ENV === 'development';
29
+ /** 附加启动配置名称
2
30
  * @example
3
31
  * 当通过以下命令启动时, 此时 CUSTOMCONFIG 为 test
4
32
  * ```sh
5
33
  * npm run start --config=test
6
34
  * ```
7
- */export const CUSTOMCONFIG=process.env.npm_config_config||t.config;let n=Object.keys(process.env);export const hasEslintConfig=-1!==n.findIndex(e=>e.startsWith("npm_package_eslintConfig_"));export const hasStylelintConfig=-1!==n.findIndex(e=>e.startsWith("npm_package_stylelint_"));
35
+ */ export const CUSTOMCONFIG = process.env.npm_config_config || yarnArgv.config;
36
+ const envKeys = Object.keys(process.env);
37
+ export const hasEslintConfig = envKeys.findIndex((k)=>k.startsWith('npm_package_eslintConfig_')) !== -1;
38
+ export const hasStylelintConfig = envKeys.findIndex((k)=>k.startsWith('npm_package_stylelint_')) !== -1;
package/lib/prod.js CHANGED
@@ -1,5 +1,65 @@
1
- import e from"css-minimizer-webpack-plugin";import i from"mini-css-extract-plugin";import m from"terser-webpack-plugin";import n from"webpack";import{BundleAnalyzerPlugin as o}from"webpack-bundle-analyzer";import{merge as s}from"webpack-merge";import{clientConfig as r}from"./common.js";import{CONFIG as t}from"./config.js";import{getMinifyOption as p}from"./minify.js";let{optimize:{MinChunkSizePlugin:l}}=n,{cssnanoMinify:u,swcMinify:a}=e,c="swc"===t.compiler,f=[];t.minifier&&(t.minifier.js&&f.push(new m(p(t.minifier.js?.type||(c?"swc":"terser"),t.minifier.js?.options))),t.minifier.css&&f.push(new e({minify:{swc:a,cssnano:u}[t.minifier.css?.type||(c?"swc":"cssnano")],minimizerOptions:t.minifier.css?.options})));let d={splitChunks:t.splitChunk,runtimeChunk:t.runtimeChunk,chunkIds:"named",moduleIds:"named",// parent chunk中解决了的chunk会被删除
2
- removeAvailableModules:!0,// 删除空的chunks
3
- removeEmptyChunks:!0,// 合并重复的chunk
4
- mergeDuplicateChunks:!0,mangleWasmImports:!0,minimize:!0,minimizer:f},k=s(r,{devtool:!1===t.devtool||t.devtool?t.devtool:"cheap-module-source-map",mode:"production",optimization:d,plugins:[// 压缩 css
5
- new i({filename:"style/[name].bundle.css",chunkFilename:"style/[name].chunk.css",experimentalUseImportModule:!0}),t.bundleAnalyzer&&new o(t.bundleAnalyzer),t.splitChunk&&new l({minChunkSize:1e4})].filter(Boolean)});export default[k];
1
+ import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
2
+ import MiniCssExtractPlugin from 'mini-css-extract-plugin';
3
+ import TerserPlugin from 'terser-webpack-plugin';
4
+ import webpack from 'webpack';
5
+ import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
6
+ import { merge } from 'webpack-merge';
7
+ import { clientConfig } from './common.js';
8
+ import { CONFIG } from './config.js';
9
+ import { getMinifyOption } from './minify.js';
10
+ const { optimize: { MinChunkSizePlugin } } = webpack;
11
+ const { cssnanoMinify, swcMinify } = CssMinimizerPlugin;
12
+ const swcCompiler = CONFIG.compiler === 'swc';
13
+ const defaultJsMiniify = swcCompiler ? 'swc' : 'terser';
14
+ const defaultCssMiniify = swcCompiler ? 'swc' : 'cssnano';
15
+ const cssMinify = {
16
+ swc: swcMinify,
17
+ cssnano: cssnanoMinify
18
+ };
19
+ const minimizer = [];
20
+ if (CONFIG.minifier) {
21
+ if (CONFIG.minifier.js) {
22
+ minimizer.push(new TerserPlugin(getMinifyOption(CONFIG.minifier.js?.type || defaultJsMiniify, CONFIG.minifier.js?.options)));
23
+ }
24
+ if (CONFIG.minifier.css) {
25
+ minimizer.push(new CssMinimizerPlugin({
26
+ minify: cssMinify[CONFIG.minifier.css?.type || defaultCssMiniify],
27
+ minimizerOptions: CONFIG.minifier.css?.options
28
+ }));
29
+ }
30
+ }
31
+ const optimization = {
32
+ splitChunks: CONFIG.splitChunk,
33
+ runtimeChunk: CONFIG.runtimeChunk,
34
+ chunkIds: 'named',
35
+ moduleIds: 'named',
36
+ // parent chunk中解决了的chunk会被删除
37
+ removeAvailableModules: true,
38
+ // 删除空的chunks
39
+ removeEmptyChunks: true,
40
+ // 合并重复的chunk
41
+ mergeDuplicateChunks: true,
42
+ mangleWasmImports: true,
43
+ minimize: true,
44
+ minimizer: minimizer
45
+ };
46
+ const client = merge(clientConfig, {
47
+ devtool: CONFIG.devtool === false || CONFIG.devtool ? CONFIG.devtool : 'cheap-module-source-map',
48
+ mode: 'production',
49
+ optimization: optimization,
50
+ plugins: [
51
+ // 压缩 css
52
+ new MiniCssExtractPlugin({
53
+ filename: 'style/[name].bundle.css',
54
+ chunkFilename: 'style/[name].chunk.css',
55
+ experimentalUseImportModule: true
56
+ }),
57
+ CONFIG.bundleAnalyzer && new BundleAnalyzerPlugin(CONFIG.bundleAnalyzer),
58
+ CONFIG.splitChunk && new MinChunkSizePlugin({
59
+ minChunkSize: 10000
60
+ })
61
+ ].filter(Boolean)
62
+ });
63
+ export default [
64
+ client
65
+ ];
@@ -1,8 +1,47 @@
1
- import t from"events";class e extends t{constructor(t={}){super(),this.data=t}setData(t,e){e!==this.data[t]&&(this.data[t]=e,this.emit("change",t,e))}getData(t){return this.data[t]}// removeData(key: keyof T) {
2
- // if (Object.prototype.hasOwnProperty.call(this.data, key)) {
3
- // delete this.data[key];
4
- // this.emit('change', key, null);
5
- // }
6
- // }
7
- // 实现迭代器接口
8
- [Symbol.iterator](){let t=Object.keys(this.data),e=0;return{next:()=>{if(e<t.length){let a=t[e++];return{value:[a,this.data[a]],done:!1}}return{value:void 0,done:!0}}}}}export default e;
1
+ import EventEmitter from 'events';
2
+ class ReactiveObject extends EventEmitter {
3
+ data;
4
+ constructor(props = {}){
5
+ super();
6
+ this.data = props;
7
+ }
8
+ setData(key, value) {
9
+ if (value !== this.data[key]) {
10
+ this.data[key] = value;
11
+ this.emit('change', key, value);
12
+ }
13
+ }
14
+ getData(key) {
15
+ return this.data[key];
16
+ }
17
+ // removeData(key: keyof T) {
18
+ // if (Object.prototype.hasOwnProperty.call(this.data, key)) {
19
+ // delete this.data[key];
20
+ // this.emit('change', key, null);
21
+ // }
22
+ // }
23
+ // 实现迭代器接口
24
+ [Symbol.iterator]() {
25
+ const keys = Object.keys(this.data);
26
+ let index = 0;
27
+ return {
28
+ next: ()=>{
29
+ if (index < keys.length) {
30
+ const key = keys[index++];
31
+ return {
32
+ value: [
33
+ key,
34
+ this.data[key]
35
+ ],
36
+ done: false
37
+ };
38
+ }
39
+ return {
40
+ value: void 0,
41
+ done: true
42
+ };
43
+ }
44
+ };
45
+ }
46
+ }
47
+ export default ReactiveObject;
package/lib/rem.js CHANGED
@@ -1 +1,6 @@
1
- import{CONFIG as e}from"./config.js";let t="";e.rem.designSize&&(t=`!function(e,n){function t(){let n=e.documentElement,t=n.clientWidth||e.body.clientWidth,i=t<=375?375:${e.rem.designSize},o=t;o=t<=375?t:t<=${e.rem.designSize}?i:t;let d=16/i*o+"px";d!==n.style.fontSize&&(n.style.fontSize=d)}t(),"addEventListener"in e&&n.addEventListener("orientationchange"in n?"orientationchange":"resize",t,!1)}(document,window);`);export default t;
1
+ import { CONFIG } from './config.js';
2
+ let rem = '';
3
+ if (CONFIG.rem.designSize) {
4
+ rem = `!function(e,n){function t(){let n=e.documentElement,t=n.clientWidth||e.body.clientWidth,i=t<=375?375:${CONFIG.rem.designSize},o=t;o=t<=375?t:t<=${CONFIG.rem.designSize}?i:t;let d=16/i*o+"px";d!==n.style.fontSize&&(n.style.fontSize=d)}t(),"addEventListener"in e&&n.addEventListener("orientationchange"in n?"orientationchange":"resize",t,!1)}(document,window);`;
5
+ }
6
+ export default rem;
@@ -1 +1,27 @@
1
- import*as e from"fs";import s from"enhanced-resolve";let{CachedInputFileSystem:o,ResolverFactory:n}=s,m=n.createResolver({fileSystem:new o(e,4e3),conditionNames:["node"],extensions:[".js",".json",".node"],useSyncFileSystemCalls:!0,mainFields:["esm","module","main"]});export default m;
1
+ import * as fs from 'fs';
2
+ import enhancedResolve from 'enhanced-resolve';
3
+ const { CachedInputFileSystem, ResolverFactory } = enhancedResolve;
4
+ /**
5
+ * @examples
6
+ * ```javascript
7
+ * // 获取 react 包入口路径,优先 esm,兜底 cjs
8
+ * resolverSync.resolveSync({}, process.cwd(), "react")
9
+ * ```
10
+ */ const resolverSync = ResolverFactory.createResolver({
11
+ fileSystem: new CachedInputFileSystem(fs, 4000),
12
+ conditionNames: [
13
+ 'node'
14
+ ],
15
+ extensions: [
16
+ '.js',
17
+ '.json',
18
+ '.node'
19
+ ],
20
+ useSyncFileSystemCalls: true,
21
+ mainFields: [
22
+ 'esm',
23
+ 'module',
24
+ 'main'
25
+ ]
26
+ });
27
+ export default resolverSync;
package/lib/routes.js CHANGED
@@ -1,4 +1,196 @@
1
- let e,t;import{readFileSync as r,readdirSync as o,statSync as s}from"fs";import{join as n,relative as p}from"path";import{watch as i}from"chokidar";import{load as a}from"js-yaml";import{hasCustomRouter as l}from"./config.js";import c from"./paths.js";import{FRAMEWORK as m,FRAMEWORKNAME as u,createElement as f,isLibrary as d,isReact as x,isSolid as h}from"./process-env.js";import g from"./reactive-object.js";let $=/^---\n([\s\S]+?)\n---\n/,j=h?"component":"element";function y(e){return e.replace(/\$/g,":").replace(/^index\.tsx?$/,"/").replace(/^README\.mdx?$/,"/")}function N(e,t){let{regex:i,alia:l,base:c=e,outputSource:m}=t,u=o(e);return u.reduce((o,u)=>{let f=n(e,u),d=s(f);if(d.isDirectory()){let e=N(f,{...t,base:c});if(e.length>0){let t={},r={path:y(u),key:y(p(c,f))};if(m)Object.assign(t,{children:e});else{let o=e.findIndex(e=>"/"===e.path||r.path===e.path),s=e.splice(o,1)[0];e.length?Object.assign(t,!h&&s,{children:[h&&{...s,path:r.path===s.path?"/":s.path},...e].filter(Boolean)}):Object.assign(t,s)}o.push(Object.assign(t,r))}}else if(i.test(f)){let e=r(f,{encoding:"utf-8"}),t=function(e){let t=e.match($);return t&&t[1]?t[1].trim():null}(e),s=t?a(t):{},i=p(c,f),u=y(i);o.push(Object.assign({path:u.split("/").slice(-2,-1)?.join("")||"/",key:u.replace(/\/?index.tsx?$/,"/").replace(/\/?README.mdx?$/,"/").split("/").filter(Boolean).join("/"),meta:{...s}},l&&{[j]:`rr(() => import(/* webpackChunkName: '${i}' */'${n(l,i)}'))rr`},m&&{codes:function(e){let t;let r={},o=/```(.+?)\n([\s\S]*?)\n```/g;for(;null!==(t=o.exec(e));){let[,e="jsx",o]=t,s=e.split(" ").pop()||"jsx";r[s]=o.trim()}return Object.keys(r).length?r:{jsx:e}}(e.replace($,"").replace(/^\n+|\n+$/g,""))}))}return o},[])}export const routesModuleName="@app/routes";export const route=new g({[routesModuleName]:"export default []"});export const exampleModuleName="@app/example";export const examples=new g;let T=`${h?"() => ":""}${f}(SuspenseComp, { comp: $1 })`,k=`import { ${f} } from "${u}";import SuspenseComp from "@app/suspense";${x?'import prefix from "@app/prefix-router";':""}`;l&&(k+='import merge from "@app/merge-router";import customRouter from "@/router";'),["react","solid"].includes(m)||(T="$1",k="");export let routes=[];function D(e){return`${k}const routes = [{ path: "/", children: [${h?'{ path: "/" },':""} ${e}] }];const _routes = ${l?'merge([...routes, ...customRouter], "path")':"routes"};export default ${x?"prefix(_routes)":"_routes"};`}function E(e,t,r){let o=i(e,{ignored:(e,r)=>{if(r)return!r.isDirectory()&&t.test(e)},persistent:!0,ignoreInitial:!1});o.on("add",()=>{r()}).on("change",()=>{r()}).on("unlink",()=>{r()}),process.on("SIGINT",function(){o.close()})}d?(// router
2
- E(c.componentsPath,/(?<!README\.mdx?)$/,function(){clearTimeout(e),e=setTimeout(()=>{clearTimeout(e),routes=N(c.componentsPath,{regex:/README\.mdx?$/,alia:"@pkg"}),route.setData(routesModuleName,D(JSON.stringify(routes).replace(/"rr\((.+?)\)rr"/g,T).slice(1,-1)))},100)}),// demos
3
- E(c.componentsPath,/(?<!\/examples\/(.+)\.md)$/,function(){clearTimeout(t),t=setTimeout(()=>{clearTimeout(t),N(c.componentsPath,{regex:/\/examples\/(.+)\.md$/,outputSource:!0}).forEach(e=>{let t=["@app/example",e.key].filter(Boolean).join("/"),r=e.children?.[0].children?.filter(e=>e.codes)?.map(e=>({title:e.path.replace(/.md$/,""),order:0,...e.meta,codes:e.codes})).sort((e,t)=>e.order-t.order)||[];examples.setData(t,`export default ${JSON.stringify(r)};`)})},100)})):// router
4
- E(c.pagesPath,/(?<!index\.tsx?)$/,function(){clearTimeout(e),e=setTimeout(()=>{clearTimeout(e),routes=N(c.pagesPath,{regex:/index\.tsx?$/,alia:"@/pages"}),route.setData(routesModuleName,D(JSON.stringify(routes).replace(/"rr\((.+?)\)rr"/g,T).slice(1,-1)))},100)});
1
+ import { readFileSync, readdirSync, statSync } from 'fs';
2
+ import { join, relative } from 'path';
3
+ import { watch } from 'chokidar';
4
+ import { load } from 'js-yaml';
5
+ import { hasCustomRouter } from './config.js';
6
+ import paths from './paths.js';
7
+ import { FRAMEWORK, FRAMEWORKNAME, createElement, isLibrary, isReact, isSolid } from './process-env.js';
8
+ import ReactiveObject from './reactive-object.js';
9
+ const frontmatterRegex = /^---\n([\s\S]+?)\n---\n/;
10
+ function extractFrontmatter(md) {
11
+ const matches = md.match(frontmatterRegex);
12
+ return matches && matches[1] ? matches[1].trim() : null;
13
+ }
14
+ const elename = isSolid ? 'component' : 'element';
15
+ function extractCode(codeStr) {
16
+ const codes = {};
17
+ const regex = /```(.+?)\n([\s\S]*?)\n```/g;
18
+ let match;
19
+ while((match = regex.exec(codeStr)) !== null){
20
+ const [, language = 'jsx', source] = match;
21
+ const lang = language.split(' ').pop() || 'jsx';
22
+ codes[lang] = source.trim();
23
+ }
24
+ return Object.keys(codes).length ? codes : {
25
+ jsx: codeStr
26
+ };
27
+ }
28
+ function prefixPath(src) {
29
+ return src.replace(/\$/g, ':').replace(/^index\.tsx?$/, '/').replace(/^README\.mdx?$/, '/');
30
+ }
31
+ function getTree(directory, option) {
32
+ const { regex, alia, base = directory, outputSource } = option;
33
+ const files = readdirSync(directory);
34
+ return files.reduce((tree, file)=>{
35
+ const filePath = join(directory, file);
36
+ const stats = statSync(filePath);
37
+ if (stats.isDirectory()) {
38
+ const children = getTree(filePath, {
39
+ ...option,
40
+ base
41
+ });
42
+ if (children.length > 0) {
43
+ const item = {};
44
+ const baseItem = {
45
+ path: prefixPath(file),
46
+ key: prefixPath(relative(base, filePath))
47
+ };
48
+ if (outputSource) {
49
+ Object.assign(item, {
50
+ children
51
+ });
52
+ } else {
53
+ const baseIdx = children.findIndex((c)=>c.path === '/' || baseItem.path === c.path);
54
+ const frist = children.splice(baseIdx, 1)[0];
55
+ if (children.length) {
56
+ Object.assign(item, !isSolid && frist, {
57
+ children: [
58
+ isSolid && {
59
+ ...frist,
60
+ path: baseItem.path === frist.path ? '/' : frist.path
61
+ },
62
+ ...children
63
+ ].filter(Boolean)
64
+ });
65
+ } else {
66
+ Object.assign(item, frist);
67
+ }
68
+ }
69
+ tree.push(Object.assign(item, baseItem));
70
+ }
71
+ } else if (regex.test(filePath)) {
72
+ const source = readFileSync(filePath, {
73
+ encoding: 'utf-8'
74
+ });
75
+ const frontmatter = extractFrontmatter(source);
76
+ const meta = frontmatter ? load(frontmatter) : {};
77
+ const reslove = relative(base, filePath);
78
+ const realPath = prefixPath(reslove);
79
+ tree.push(Object.assign({
80
+ path: realPath.split('/').slice(-2, -1)?.join('') || '/',
81
+ key: realPath.replace(/\/?index.tsx?$/, '/').replace(/\/?README.mdx?$/, '/').split('/').filter(Boolean).join('/'),
82
+ meta: {
83
+ ...meta
84
+ }
85
+ }, alia && {
86
+ [elename]: `rr(() => import(/* webpackChunkName: '${reslove}' */'${join(alia, reslove)}'))rr`
87
+ }, outputSource && {
88
+ codes: extractCode(source.replace(frontmatterRegex, '').replace(/^\n+|\n+$/g, ''))
89
+ }));
90
+ }
91
+ return tree;
92
+ }, []);
93
+ }
94
+ export const routesModuleName = '@app/routes';
95
+ export const route = new ReactiveObject({
96
+ [routesModuleName]: 'export default []'
97
+ });
98
+ export const exampleModuleName = '@app/example';
99
+ export const examples = new ReactiveObject();
100
+ let replaceStr = `${isSolid ? '() => ' : ''}${createElement}(SuspenseComp, { comp: $1 })`;
101
+ let prefixStr = `import { ${createElement} } from "${FRAMEWORKNAME}";import SuspenseComp from "@app/suspense";${isReact ? 'import prefix from "@app/prefix-router";' : ''}`;
102
+ if (hasCustomRouter) {
103
+ prefixStr += 'import merge from "@app/merge-router";import customRouter from "@/router";';
104
+ }
105
+ if (![
106
+ 'react',
107
+ 'solid'
108
+ ].includes(FRAMEWORK)) {
109
+ replaceStr = '$1';
110
+ prefixStr = '';
111
+ }
112
+ export let routes = [];
113
+ let timerRoutes;
114
+ function updateData(tree) {
115
+ return `${prefixStr}const routes = [{ path: "/", children: [${isSolid ? '{ path: "/" },' : ''} ${tree}] }];const _routes = ${hasCustomRouter ? 'merge([...routes, ...customRouter], "path")' : 'routes'};export default ${isReact ? 'prefix(_routes)' : '_routes'};`;
116
+ }
117
+ function generatorLibraryRouter() {
118
+ clearTimeout(timerRoutes);
119
+ timerRoutes = setTimeout(()=>{
120
+ clearTimeout(timerRoutes);
121
+ routes = getTree(paths.componentsPath, {
122
+ regex: /README\.mdx?$/,
123
+ alia: '@pkg'
124
+ });
125
+ route.setData(routesModuleName, updateData(JSON.stringify(routes).replace(/"rr\((.+?)\)rr"/g, replaceStr).slice(1, -1)));
126
+ }, 100);
127
+ }
128
+ let timerExample;
129
+ function generatorLibraryDemo() {
130
+ clearTimeout(timerExample);
131
+ timerExample = setTimeout(()=>{
132
+ clearTimeout(timerExample);
133
+ getTree(paths.componentsPath, {
134
+ regex: /\/examples\/(.+)\.md$/,
135
+ outputSource: true
136
+ }).forEach((item)=>{
137
+ const _name = [
138
+ exampleModuleName,
139
+ item.key
140
+ ].filter(Boolean).join('/');
141
+ const data = item.children?.[0].children?.filter((e)=>e.codes)?.map((e)=>({
142
+ title: e.path.replace(/.md$/, ''),
143
+ order: 0,
144
+ ...e.meta,
145
+ codes: e.codes
146
+ })).sort((a, b)=>a.order - b.order) || [];
147
+ examples.setData(_name, `export default ${JSON.stringify(data)};`);
148
+ });
149
+ }, 100);
150
+ }
151
+ function watchFiles(root, ignored, call) {
152
+ const ignoredRouter = (src, stats)=>{
153
+ if (stats) {
154
+ if (stats.isDirectory()) {
155
+ return false;
156
+ }
157
+ return ignored.test(src);
158
+ }
159
+ return void 0;
160
+ };
161
+ const watcher = watch(root, {
162
+ ignored: ignoredRouter,
163
+ persistent: true,
164
+ ignoreInitial: false
165
+ });
166
+ watcher.on('add', ()=>{
167
+ call();
168
+ }).on('change', ()=>{
169
+ call();
170
+ }).on('unlink', ()=>{
171
+ call();
172
+ });
173
+ process.on('SIGINT', function() {
174
+ watcher.close();
175
+ });
176
+ }
177
+ function generatorRouter() {
178
+ clearTimeout(timerRoutes);
179
+ timerRoutes = setTimeout(()=>{
180
+ clearTimeout(timerRoutes);
181
+ routes = getTree(paths.pagesPath, {
182
+ regex: /index\.tsx?$/,
183
+ alia: '@/pages'
184
+ });
185
+ route.setData(routesModuleName, updateData(JSON.stringify(routes).replace(/"rr\((.+?)\)rr"/g, replaceStr).slice(1, -1)));
186
+ }, 100);
187
+ }
188
+ if (isLibrary) {
189
+ // router
190
+ watchFiles(paths.componentsPath, /(?<!README\.mdx?)$/, generatorLibraryRouter);
191
+ // demos
192
+ watchFiles(paths.componentsPath, /(?<!\/examples\/(.+)\.md)$/, generatorLibraryDemo);
193
+ } else {
194
+ // router
195
+ watchFiles(paths.pagesPath, /(?<!index\.tsx?)$/, generatorRouter);
196
+ }
package/lib/seo.js CHANGED
@@ -1,2 +1,41 @@
1
- import{existsSync as t,mkdirSync as o,writeFileSync as r}from"fs";import{join as i}from"path";import{outputConfig as s}from"./common.js";import{CONFIG as e}from"./config.js";import{routes as m}from"./routes.js";import{resolveProgramPath as n}from"./utils.js";function p(t,o){try{r(t,o,"utf-8")}catch(t){//
2
- }}export const seo=()=>{let{domain:r,nojekyll:f,path:a}=e.seo||{},c=a&&n(a)||s?.path;if(!r||!c)return;t(c)||o(c);let h=e.basename,l=h.endsWith("/")?h:`${h}/`;p(i(c,"CNAME"),r),p(i(c,"robots"),`Sitemap: https://${r}${l}sitemap.txt`);let u=[];!function t(o){o.forEach(o=>{u.push(`https://${r}${l}${o.key}`),Array.isArray(o.children)&&t(o.children)})}(m),p(i(c,"sitemap.txt"),u.join("\n")),f&&p(i(c,".nojekyll"),"")};
1
+ import { existsSync, mkdirSync, writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { outputConfig } from './common.js';
4
+ import { CONFIG } from './config.js';
5
+ import { routes } from './routes.js';
6
+ import { resolveProgramPath } from './utils.js';
7
+ function writeFile(path, data) {
8
+ try {
9
+ writeFileSync(path, data, 'utf-8');
10
+ } catch (error) {
11
+ //
12
+ }
13
+ }
14
+ export const seo = ()=>{
15
+ const { domain, nojekyll, path } = CONFIG.seo || {};
16
+ const baseDir = path && resolveProgramPath(path) || outputConfig?.path;
17
+ if (!domain || !baseDir) {
18
+ return;
19
+ }
20
+ if (!existsSync(baseDir)) {
21
+ mkdirSync(baseDir);
22
+ }
23
+ const routeBase = CONFIG.basename;
24
+ const base = routeBase.endsWith('/') ? routeBase : `${routeBase}/`;
25
+ writeFile(join(baseDir, 'CNAME'), domain);
26
+ writeFile(join(baseDir, 'robots'), `Sitemap: https://${domain}${base}sitemap.txt`);
27
+ const sitemap = [];
28
+ function getSiteMap(list) {
29
+ list.forEach((item)=>{
30
+ sitemap.push(`https://${domain}${base}${item.key}`);
31
+ if (Array.isArray(item.children)) {
32
+ getSiteMap(item.children);
33
+ }
34
+ });
35
+ }
36
+ getSiteMap(routes);
37
+ writeFile(join(baseDir, 'sitemap.txt'), sitemap.join('\n'));
38
+ if (nojekyll) {
39
+ writeFile(join(baseDir, '.nojekyll'), '');
40
+ }
41
+ };