@moneko/core 3.1.0-beta.2 → 3.1.0-beta.3
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.
- package/lib/app-entry.js +32 -1
- package/lib/app.js +40 -2
- package/lib/cleanup.js +19 -1
- package/lib/common.js +221 -2
- package/lib/config.js +230 -1
- package/lib/coverage.js +33 -3
- package/lib/dev.js +89 -5
- package/lib/docs.js +107 -2
- package/lib/done.js +11 -1
- package/lib/esm.js +7 -1
- package/lib/fallback.js +6 -1
- package/lib/generate-api.js +341 -3
- package/lib/has-pkg.js +12 -1
- package/lib/html-add-entry-attr.js +31 -10
- package/lib/html-plugin-option.js +45 -1
- package/lib/index.js +1 -1
- package/lib/locales.js +90 -3
- package/lib/merge-router.js +1 -1
- package/lib/minify.js +47 -2
- package/lib/modify-vars.js +11 -1
- package/lib/module-federation.js +46 -1
- package/lib/module.config.js +228 -3
- package/lib/net.js +33 -1
- package/lib/normalize-css.js +6 -1
- package/lib/object-listener.js +28 -1
- package/lib/paths.js +20 -1
- package/lib/prefix-router.js +6 -1
- package/lib/process-env.js +33 -1
- package/lib/prod.js +64 -5
- package/lib/rem.js +6 -1
- package/lib/resolver-sync.js +27 -1
- package/lib/routes.js +209 -4
- package/lib/seo.js +41 -2
- package/lib/swcrc.js +107 -2
- package/lib/tsloader.config.js +26 -2
- package/lib/utils.js +68 -6
- package/lib/virtual-module-plugin.js +63 -1
- package/lib/virtual-modules.js +37 -1
- package/lib/yarn-argv.js +9 -1
- package/package.json +2 -2
package/lib/process-env.js
CHANGED
|
@@ -1 +1,33 @@
|
|
|
1
|
-
import{readFileSync
|
|
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
|
+
const frameworkMap = {
|
|
19
|
+
react: 'react',
|
|
20
|
+
solid: 'solid-js'
|
|
21
|
+
};
|
|
22
|
+
export const FRAMEWORKNAME = frameworkMap[FRAMEWORK];
|
|
23
|
+
export const PACKAGENAME = process.env.npm_package_name;
|
|
24
|
+
export const PACKAGEVERSION = process.env.npm_package_version;
|
|
25
|
+
const pkg = readFileSync(`${paths.corePath}/../package.json`, {
|
|
26
|
+
encoding: 'utf-8'
|
|
27
|
+
});
|
|
28
|
+
export const pkgName = JSON.parse(pkg).name;
|
|
29
|
+
export const isDev = process.env.NODE_ENV === 'development';
|
|
30
|
+
export const CUSTOMCONFIG = process.env.npm_config_config || yarnArgv.config;
|
|
31
|
+
const envKeys = Object.keys(process.env);
|
|
32
|
+
export const hasEslintConfig = envKeys.findIndex((k)=>k.startsWith('npm_package_eslintConfig_')) !== -1;
|
|
33
|
+
export const hasStylelintConfig = envKeys.findIndex((k)=>k.startsWith('npm_package_stylelint_')) !== -1;
|
package/lib/prod.js
CHANGED
|
@@ -1,5 +1,64 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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 } = 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
|
+
minimize: true,
|
|
43
|
+
minimizer: minimizer
|
|
44
|
+
};
|
|
45
|
+
const client = merge(clientConfig, {
|
|
46
|
+
devtool: CONFIG.devtool === false || CONFIG.devtool ? CONFIG.devtool : 'cheap-module-source-map',
|
|
47
|
+
mode: 'production',
|
|
48
|
+
optimization: optimization,
|
|
49
|
+
plugins: [
|
|
50
|
+
// 压缩 css
|
|
51
|
+
new MiniCssExtractPlugin({
|
|
52
|
+
filename: 'style/[name].bundle.css',
|
|
53
|
+
chunkFilename: 'style/[name].chunk.css',
|
|
54
|
+
experimentalUseImportModule: true
|
|
55
|
+
}),
|
|
56
|
+
CONFIG.bundleAnalyzer && new BundleAnalyzerPlugin(CONFIG.bundleAnalyzer),
|
|
57
|
+
CONFIG.splitChunk && new optimize.MinChunkSizePlugin({
|
|
58
|
+
minChunkSize: 10000
|
|
59
|
+
})
|
|
60
|
+
].filter(Boolean)
|
|
61
|
+
});
|
|
62
|
+
export default [
|
|
63
|
+
client
|
|
64
|
+
];
|
package/lib/rem.js
CHANGED
|
@@ -1 +1,6 @@
|
|
|
1
|
-
import{CONFIG
|
|
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;
|
package/lib/resolver-sync.js
CHANGED
|
@@ -1 +1,27 @@
|
|
|
1
|
-
import*as
|
|
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,209 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 objectListener from './object-listener.js';
|
|
7
|
+
import paths from './paths.js';
|
|
8
|
+
import { FRAMEWORK, FRAMEWORKNAME, createElement, isLibrary, isReact, isSolid } from './process-env.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 route = objectListener({
|
|
95
|
+
name: '@app/routes',
|
|
96
|
+
data: 'export default []'
|
|
97
|
+
});
|
|
98
|
+
export const example = objectListener({
|
|
99
|
+
name: '@app/example',
|
|
100
|
+
data: {}
|
|
101
|
+
});
|
|
102
|
+
let replaceStr = `${isSolid ? '() => ' : ''}${createElement}(SuspenseComp, { comp: $1 })`;
|
|
103
|
+
let prefixStr = `import { ${createElement} } from "${FRAMEWORKNAME}";import SuspenseComp from "@app/suspense";${isReact ? 'import prefix from "@app/prefix-router";' : ''}`;
|
|
104
|
+
if (hasCustomRouter) {
|
|
105
|
+
prefixStr += 'import merge from "@app/merge-router";import customRouter from "@/router";';
|
|
106
|
+
}
|
|
107
|
+
if (![
|
|
108
|
+
'react',
|
|
109
|
+
'solid'
|
|
110
|
+
].includes(FRAMEWORK)) {
|
|
111
|
+
replaceStr = '$1';
|
|
112
|
+
prefixStr = '';
|
|
113
|
+
}
|
|
114
|
+
export let routes = [];
|
|
115
|
+
let timerRoutes;
|
|
116
|
+
function updateData(tree) {
|
|
117
|
+
return `${prefixStr}const routes = [{ path: "/", children: [${isSolid ? '{ path: "/" },' : ''} ${tree}] }];const _routes = ${hasCustomRouter ? 'merge([...routes, ...customRouter], "path")' : 'routes'};export default ${isReact ? 'prefix(_routes)' : '_routes'};`;
|
|
118
|
+
}
|
|
119
|
+
function generatorLibraryRouter() {
|
|
120
|
+
clearTimeout(timerRoutes);
|
|
121
|
+
timerRoutes = setTimeout(()=>{
|
|
122
|
+
clearTimeout(timerRoutes);
|
|
123
|
+
routes = getTree(paths.componentsPath, {
|
|
124
|
+
regex: /README\.mdx?$/,
|
|
125
|
+
alia: '@pkg'
|
|
126
|
+
});
|
|
127
|
+
const tree = JSON.stringify(routes).replace(/"rr\((.+?)\)rr"/g, replaceStr).slice(1, -1);
|
|
128
|
+
Object.assign(route.data, {
|
|
129
|
+
data: updateData(tree)
|
|
130
|
+
});
|
|
131
|
+
}, 100);
|
|
132
|
+
}
|
|
133
|
+
let timerExample;
|
|
134
|
+
function generatorLibraryDemo() {
|
|
135
|
+
clearTimeout(timerExample);
|
|
136
|
+
timerExample = setTimeout(()=>{
|
|
137
|
+
clearTimeout(timerExample);
|
|
138
|
+
const exampleNext = {};
|
|
139
|
+
getTree(paths.componentsPath, {
|
|
140
|
+
regex: /\/examples\/(.+)\.md$/,
|
|
141
|
+
outputSource: true
|
|
142
|
+
}).forEach((item)=>{
|
|
143
|
+
const _name = [
|
|
144
|
+
example.data.name,
|
|
145
|
+
item.key
|
|
146
|
+
].filter(Boolean).join('/');
|
|
147
|
+
const data = item.children?.[0].children?.filter((e)=>e.codes)?.map((e)=>({
|
|
148
|
+
title: e.path.replace(/.md$/, ''),
|
|
149
|
+
order: 0,
|
|
150
|
+
...e.meta,
|
|
151
|
+
codes: e.codes
|
|
152
|
+
})).sort((a, b)=>a.order - b.order);
|
|
153
|
+
Object.assign(exampleNext, {
|
|
154
|
+
[_name]: `export default ${JSON.stringify(data)};`
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
Object.assign(example.data, {
|
|
158
|
+
data: exampleNext
|
|
159
|
+
});
|
|
160
|
+
}, 100);
|
|
161
|
+
}
|
|
162
|
+
function watchFiles(root, ignored, call) {
|
|
163
|
+
const ignoredRouter = (src, stats)=>{
|
|
164
|
+
if (stats) {
|
|
165
|
+
if (stats?.isDirectory()) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
return ignored.test(src);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const watcher = watch(root, {
|
|
172
|
+
ignored: ignoredRouter,
|
|
173
|
+
persistent: true,
|
|
174
|
+
ignoreInitial: false
|
|
175
|
+
});
|
|
176
|
+
watcher.on('add', ()=>{
|
|
177
|
+
call();
|
|
178
|
+
}).on('change', ()=>{
|
|
179
|
+
call();
|
|
180
|
+
}).on('unlink', ()=>{
|
|
181
|
+
call();
|
|
182
|
+
});
|
|
183
|
+
process.on('SIGINT', function() {
|
|
184
|
+
watcher.close();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
function generatorRouter() {
|
|
188
|
+
clearTimeout(timerRoutes);
|
|
189
|
+
timerRoutes = setTimeout(()=>{
|
|
190
|
+
clearTimeout(timerRoutes);
|
|
191
|
+
routes = getTree(paths.pagesPath, {
|
|
192
|
+
regex: /index\.tsx?$/,
|
|
193
|
+
alia: '@/pages'
|
|
194
|
+
});
|
|
195
|
+
const tree = JSON.stringify(routes).replace(/"rr\((.+?)\)rr"/g, replaceStr).slice(1, -1);
|
|
196
|
+
Object.assign(route.data, {
|
|
197
|
+
data: updateData(tree)
|
|
198
|
+
});
|
|
199
|
+
}, 100);
|
|
200
|
+
}
|
|
201
|
+
if (isLibrary) {
|
|
202
|
+
// router
|
|
203
|
+
watchFiles(paths.componentsPath, /(?<!README\.mdx?)$/, generatorLibraryRouter);
|
|
204
|
+
// demos
|
|
205
|
+
watchFiles(paths.componentsPath, /(?<!\/examples\/(.+)\.md)$/, generatorLibraryDemo);
|
|
206
|
+
} else {
|
|
207
|
+
// router
|
|
208
|
+
watchFiles(paths.pagesPath, /(?<!index\.tsx?)$/, generatorRouter);
|
|
209
|
+
}
|
package/lib/seo.js
CHANGED
|
@@ -1,2 +1,41 @@
|
|
|
1
|
-
import{existsSync
|
|
2
|
-
|
|
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
|
+
};
|
package/lib/swcrc.js
CHANGED
|
@@ -1,2 +1,107 @@
|
|
|
1
|
-
import{merge
|
|
2
|
-
|
|
1
|
+
import { merge } from 'webpack-merge';
|
|
2
|
+
import { CONFIG } from './config.js';
|
|
3
|
+
import paths from './paths.js';
|
|
4
|
+
import { isReact, isSolid, jsxImportSource } from './process-env.js';
|
|
5
|
+
// swc polyfill 策略,会复用 babel 链路,但效率比 babel 低
|
|
6
|
+
const swcPolyfill = {
|
|
7
|
+
env: {
|
|
8
|
+
targets: [
|
|
9
|
+
'>0.3%',
|
|
10
|
+
'defaults',
|
|
11
|
+
'supports es6-module',
|
|
12
|
+
'maintained node versions'
|
|
13
|
+
],
|
|
14
|
+
mode: 'entry',
|
|
15
|
+
coreJs: '3'
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
export const swcMinifyOption = {
|
|
19
|
+
compress: {
|
|
20
|
+
top_retain: [],
|
|
21
|
+
keep_infinity: true,
|
|
22
|
+
global_defs: {
|
|
23
|
+
'@alert': 'console.log'
|
|
24
|
+
},
|
|
25
|
+
pure_funcs: [
|
|
26
|
+
'console.log',
|
|
27
|
+
'console.warn',
|
|
28
|
+
'console.error',
|
|
29
|
+
'console.info'
|
|
30
|
+
],
|
|
31
|
+
toplevel: false,
|
|
32
|
+
drop_console: true,
|
|
33
|
+
drop_debugger: true,
|
|
34
|
+
module: false,
|
|
35
|
+
ecma: 2015,
|
|
36
|
+
ie8: false,
|
|
37
|
+
keep_classnames: void 0,
|
|
38
|
+
keep_fnames: false
|
|
39
|
+
},
|
|
40
|
+
mangle: true
|
|
41
|
+
};
|
|
42
|
+
function transformConfigs(config) {
|
|
43
|
+
for(let i = 0, ks = Object.keys(config), l = ks.length; i < l; i++){
|
|
44
|
+
config[ks[i]].transform = `${ks[i]}/${config[ks[i]].transform}`;
|
|
45
|
+
if (config[ks[i]].style) {
|
|
46
|
+
config[ks[i]].style = `${ks[i]}/${config[ks[i]].style}`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return config;
|
|
50
|
+
}
|
|
51
|
+
export default ((isDev = false)=>{
|
|
52
|
+
const swcOption = {
|
|
53
|
+
module: {
|
|
54
|
+
type: 'es6',
|
|
55
|
+
resolveFully: true
|
|
56
|
+
},
|
|
57
|
+
jsc: {
|
|
58
|
+
parser: {
|
|
59
|
+
syntax: 'typescript',
|
|
60
|
+
decorators: true,
|
|
61
|
+
dynamicImport: true,
|
|
62
|
+
tsx: true,
|
|
63
|
+
topLevelAwait: true,
|
|
64
|
+
importMeta: true
|
|
65
|
+
},
|
|
66
|
+
loose: true,
|
|
67
|
+
target: 'es2022',
|
|
68
|
+
externalHelpers: true,
|
|
69
|
+
transform: {
|
|
70
|
+
legacyDecorator: true,
|
|
71
|
+
decoratorMetadata: true,
|
|
72
|
+
react: {
|
|
73
|
+
runtime: 'automatic',
|
|
74
|
+
throwIfNamespace: true,
|
|
75
|
+
useBuiltins: true,
|
|
76
|
+
refresh: isReact && isDev,
|
|
77
|
+
development: isDev,
|
|
78
|
+
importSource: jsxImportSource
|
|
79
|
+
},
|
|
80
|
+
optimizer: {
|
|
81
|
+
simplify: false
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
experimental: {
|
|
85
|
+
emitAssertForImportAttributes: true,
|
|
86
|
+
cacheRoot: paths.swcCachePath,
|
|
87
|
+
plugins: [
|
|
88
|
+
[
|
|
89
|
+
'swc-plugin-another-transform-imports',
|
|
90
|
+
transformConfigs(CONFIG.importOnDemand || {})
|
|
91
|
+
],
|
|
92
|
+
isSolid && [
|
|
93
|
+
'@moneko/jsx-dom-expressions',
|
|
94
|
+
CONFIG.jsxDomExpressions || {}
|
|
95
|
+
]
|
|
96
|
+
].filter(Boolean)
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
sourceMaps: true,
|
|
100
|
+
parseMap: true
|
|
101
|
+
};
|
|
102
|
+
let swcrc = Object.assign(swcOption, !isDev && swcPolyfill);
|
|
103
|
+
if (CONFIG.swcrc) {
|
|
104
|
+
swcrc = merge(swcrc, typeof CONFIG.swcrc === 'function' ? CONFIG.swcrc(isDev) : CONFIG.swcrc);
|
|
105
|
+
}
|
|
106
|
+
return swcrc;
|
|
107
|
+
});
|
package/lib/tsloader.config.js
CHANGED
|
@@ -1,2 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import transformerFactory from 'ts-import-plugin';
|
|
3
|
+
import merge from 'webpack-merge';
|
|
4
|
+
import { CONFIG } from './config.js';
|
|
5
|
+
import { isFunction, readConf, resolveProgramPath } from './utils.js';
|
|
6
|
+
const importOnDemand = [];
|
|
7
|
+
if (Array.isArray(CONFIG.importOnDemand)) {
|
|
8
|
+
Object.assign(importOnDemand, CONFIG.importOnDemand.map((item)=>transformerFactory(item)));
|
|
9
|
+
}
|
|
10
|
+
const beforeTransformers = [
|
|
11
|
+
...importOnDemand
|
|
12
|
+
];
|
|
13
|
+
let tsLoaderConfig = {
|
|
14
|
+
transpileOnly: true,
|
|
15
|
+
getCustomTransformers: ()=>({
|
|
16
|
+
before: beforeTransformers
|
|
17
|
+
})
|
|
18
|
+
};
|
|
19
|
+
try {
|
|
20
|
+
const customTsloaderConfigPath = resolveProgramPath('tsloader.config.ts');
|
|
21
|
+
fs.accessSync(customTsloaderConfigPath, fs.constants.R_OK);
|
|
22
|
+
const customTsloaderConfig = (await readConf(customTsloaderConfigPath, 'tsloader.config')).default;
|
|
23
|
+
tsLoaderConfig = merge(tsLoaderConfig, isFunction(customTsloaderConfig) ? customTsloaderConfig(process) : customTsloaderConfig);
|
|
24
|
+
// eslint-disable-next-line no-empty
|
|
25
|
+
} catch (error) {}
|
|
26
|
+
export default tsLoaderConfig;
|
package/lib/utils.js
CHANGED
|
@@ -1,14 +1,76 @@
|
|
|
1
|
-
import{readFileSync
|
|
1
|
+
import { readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { resolve } from 'path';
|
|
3
|
+
import { transformFileSync } from '@swc/core';
|
|
4
|
+
import paths from './paths.js';
|
|
5
|
+
import resolverSync from './resolver-sync.js';
|
|
6
|
+
const exportPattern = /export\s+(?:async\s+)?(?:function|const)\s+(\w+)/g;
|
|
7
|
+
/** 获取导出标识
|
|
2
8
|
* @param {string} path 文件地址
|
|
3
9
|
* @returns {string[]} 包含的标识
|
|
4
|
-
*/export function getExportTokens(
|
|
10
|
+
*/ export function getExportTokens(path) {
|
|
11
|
+
const code = readFileSync(path, {
|
|
12
|
+
encoding: 'utf-8'
|
|
13
|
+
});
|
|
14
|
+
const tokens = [];
|
|
15
|
+
let match;
|
|
16
|
+
while(match = exportPattern.exec(code)){
|
|
17
|
+
if (!tokens.includes(match[1])) {
|
|
18
|
+
tokens.push(match[1]);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return tokens;
|
|
22
|
+
}
|
|
23
|
+
const swcOption = {
|
|
24
|
+
inputSourceMap: false,
|
|
25
|
+
sourceMaps: false,
|
|
26
|
+
module: {
|
|
27
|
+
type: 'es6'
|
|
28
|
+
},
|
|
29
|
+
jsc: {
|
|
30
|
+
parser: {
|
|
31
|
+
syntax: 'typescript'
|
|
32
|
+
},
|
|
33
|
+
loose: false
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
export function tfc(filepath) {
|
|
37
|
+
return transformFileSync(filepath, swcOption).code || '{}';
|
|
38
|
+
}
|
|
39
|
+
export function readConf(src, name) {
|
|
40
|
+
const cacheFile = `${paths.cachePath}/${name}.mjs`;
|
|
41
|
+
writeFileSync(cacheFile, tfc(src), 'utf-8');
|
|
42
|
+
return import(cacheFile);
|
|
43
|
+
}
|
|
44
|
+
export function toUpperCaseString(string) {
|
|
45
|
+
return string?.replace(/\b\w/g, (th)=>th.toUpperCase()).replace(/\./g, ' ');
|
|
46
|
+
}
|
|
47
|
+
/** 位于项目根目录下的位置
|
|
5
48
|
* @param {string} src 路径
|
|
6
49
|
* @returns {string} 位于项目根目录下的位置
|
|
7
|
-
*/export function resolveProgramPath(
|
|
50
|
+
*/ export function resolveProgramPath(src) {
|
|
51
|
+
return resolve(paths.programPath, `./${src}`);
|
|
52
|
+
}
|
|
53
|
+
/** 位于项目根目录node_modules下的位置
|
|
8
54
|
* @param {string} src 路径
|
|
9
55
|
* @returns {string} 位于项目根目录node_modules下的位置
|
|
10
|
-
*/export const resolveNodeModulesPath=
|
|
56
|
+
*/ export const resolveNodeModulesPath = (src)=>{
|
|
57
|
+
return resolveProgramPath(`node_modules/${src}`);
|
|
58
|
+
};
|
|
59
|
+
/** 获取模块真实入口位置
|
|
11
60
|
* @param {string} url 路径
|
|
12
61
|
* @returns {string} 模块真实入口路径
|
|
13
|
-
*/export const realResolve=
|
|
14
|
-
|
|
62
|
+
*/ export const realResolve = (url)=>resolverSync.resolveSync({}, paths.programPath, url) || url;
|
|
63
|
+
const funcTag = '[object Function]';
|
|
64
|
+
const asyncTag = '[object AsyncFunction]';
|
|
65
|
+
const genTag = '[object GeneratorFunction]';
|
|
66
|
+
const proxyTag = '[object Proxy]';
|
|
67
|
+
export function isObject(target) {
|
|
68
|
+
const type = typeof target;
|
|
69
|
+
return target !== null && (type == 'object' || type == 'function');
|
|
70
|
+
}
|
|
71
|
+
// eslint-disable-next-line no-unused-vars
|
|
72
|
+
export function isFunction(target) {
|
|
73
|
+
if (!isObject(target)) return false;
|
|
74
|
+
const tagType = Object.prototype.toString.call(target);
|
|
75
|
+
return tagType == funcTag || tagType == asyncTag || tagType == genTag || tagType == proxyTag;
|
|
76
|
+
}
|