lvyjs 0.2.4 → 0.2.6

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/config.js ADDED
@@ -0,0 +1,4 @@
1
+ const assetsReg = /\.(png|jpg|jpeg|gif|svg|webp|ico)$/;
2
+ const cssReg = /\.(css|scss|less|sass|less)$/;
3
+
4
+ export { assetsReg, cssReg };
@@ -0,0 +1,4 @@
1
+ const assetsReg = /\.(png|jpg|jpeg|gif|svg|webp|ico)$/
2
+ const cssReg = /\.(css|scss|less|sass|less)$/
3
+
4
+ export { assetsReg, cssReg }
@@ -0,0 +1,8 @@
1
+ /**
2
+ *
3
+ * @param input
4
+ * @returns
5
+ */
6
+ declare const ESBuild: (input: string) => Promise<string>;
7
+
8
+ export { ESBuild };
@@ -0,0 +1,64 @@
1
+ import esbuild from 'esbuild';
2
+ import { esBuildCSS } from './plugins/css.js';
3
+ import { esBuildAlias } from './plugins/alias.js';
4
+ import { esBuildAsstes } from './plugins/Asstes.js';
5
+
6
+ // 插件
7
+ const plugins = [];
8
+ /**
9
+ *
10
+ */
11
+ const initPlugins = () => {
12
+ if (typeof global.lvyConfig?.alias != 'boolean') {
13
+ plugins.push(esBuildAlias(global.lvyConfig.alias));
14
+ }
15
+ if (typeof global.lvyConfig?.assets != 'boolean') {
16
+ plugins.push(esBuildAsstes(global.lvyConfig.assets));
17
+ }
18
+ if (typeof global.lvyConfig?.styles != 'boolean') {
19
+ plugins.push(esBuildCSS(global.lvyConfig?.styles ?? {}));
20
+ }
21
+ };
22
+ /**
23
+ *
24
+ * @param input
25
+ * @returns
26
+ */
27
+ const ESBuild = async (input) => {
28
+ // 如果没有配置
29
+ if (!global.lvyConfig)
30
+ global.lvyConfig = {};
31
+ if (!global.lvyConfig.esbuild)
32
+ global.lvyConfig.esbuild = {};
33
+ // 没有插件时,检查是否有可用插件。
34
+ if (plugins.length === 0) {
35
+ // init plugisn
36
+ await initPlugins();
37
+ }
38
+ const options = global.lvyConfig?.esbuild?.options ?? {};
39
+ const pl = options?.plugins ?? [];
40
+ // 构建
41
+ const result = await esbuild.build({
42
+ // 入口文件
43
+ entryPoints: [input],
44
+ //
45
+ bundle: true,
46
+ // 平台
47
+ platform: 'node',
48
+ // 输出格式
49
+ format: 'esm',
50
+ // 不写入文件
51
+ write: false,
52
+ // 忽略所有外部依赖
53
+ external: ['*'],
54
+ ...options,
55
+ plugins: [...plugins, ...pl]
56
+ });
57
+ if (!result.outputFiles) {
58
+ return '';
59
+ }
60
+ // 返回结果
61
+ return result.outputFiles.map(file => new TextDecoder().decode(file.contents)).join('\n');
62
+ };
63
+
64
+ export { ESBuild };
@@ -0,0 +1,26 @@
1
+ import { assetsReg } from '../../config.js';
2
+ import { generateModuleContent } from '../utils/content.js';
3
+
4
+ /**
5
+ *
6
+ * @param param0
7
+ */
8
+ const esBuildAsstes = (optoins) => {
9
+ // 默认配置
10
+ const filter = optoins?.filter ?? assetsReg;
11
+ // 返回插件
12
+ return {
13
+ name: 'assets',
14
+ setup(build) {
15
+ build.onLoad({ filter }, args => {
16
+ const content = generateModuleContent(args.path);
17
+ return {
18
+ contents: content,
19
+ loader: 'js'
20
+ };
21
+ });
22
+ }
23
+ };
24
+ };
25
+
26
+ export { esBuildAsstes };
@@ -0,0 +1,44 @@
1
+ import { assetsReg, cssReg } from '../../config.js';
2
+ import { resolve } from 'path';
3
+
4
+ /**
5
+ * esbuild alias 插件
6
+ * @param alias 配置对象
7
+ * @returns 插件
8
+ */
9
+ const esBuildAlias = (alias) => {
10
+ const entries = alias?.entries;
11
+ let assets = null;
12
+ if (typeof global.lvyConfig?.assets != 'boolean') {
13
+ assets = global.lvyConfig?.assets?.filter ?? assetsReg;
14
+ }
15
+ let styles = null;
16
+ if (typeof global.lvyConfig?.styles != 'boolean') {
17
+ styles = global.lvyConfig?.styles?.filter ?? cssReg;
18
+ }
19
+ return {
20
+ name: 'alias',
21
+ setup(build) {
22
+ if (entries) {
23
+ build.onResolve({ filter: /.*/ }, args => {
24
+ const url = args.path;
25
+ const resolveDir = args.resolveDir;
26
+ if (assets?.test(url) || styles?.test(url)) {
27
+ for (const { find, replacement } of entries) {
28
+ if ((find instanceof RegExp && find.test(url)) ||
29
+ (typeof find === 'string' && url.startsWith(find))) {
30
+ let resolvedPath = url.replace(find, replacement);
31
+ return { path: resolvedPath };
32
+ }
33
+ }
34
+ return {
35
+ path: resolve(resolveDir, url)
36
+ };
37
+ }
38
+ });
39
+ }
40
+ }
41
+ };
42
+ };
43
+
44
+ export { esBuildAlias };
@@ -0,0 +1,27 @@
1
+ import { generateCSSModuleContent } from '../utils/content.js';
2
+ import { cssReg } from '../../config.js';
3
+
4
+ /**
5
+ * css资源处理插件
6
+ * @param param0
7
+ * @returns
8
+ */
9
+ const esBuildCSS = (optoins) => {
10
+ const filter = optoins?.filter || cssReg;
11
+ // 返回插件
12
+ return {
13
+ name: 'css-loader',
14
+ setup(build) {
15
+ // 加载 CSS/SCSS 文件
16
+ build.onLoad({ filter }, args => {
17
+ const contents = generateCSSModuleContent(args.path);
18
+ return {
19
+ contents: contents,
20
+ loader: 'js'
21
+ };
22
+ });
23
+ }
24
+ };
25
+ };
26
+
27
+ export { esBuildCSS };
@@ -0,0 +1,57 @@
1
+ import { join } from 'path';
2
+ import crypto from 'node:crypto';
3
+
4
+ /**
5
+ * @param inputPath
6
+ * @returns
7
+ */
8
+ const convertPath = (inputPath) => {
9
+ return process.platform === 'win32' ? inputPath.replace(/\\/g, '/') : inputPath;
10
+ };
11
+ /**
12
+ * 生成模块内容
13
+ * @param {string} relativePath 相对路径
14
+ */
15
+ const generateModuleContent = (relativePath) => {
16
+ const contents = [
17
+ 'const createUrl = (basePath, path) => {',
18
+ "const platform = ['linux', 'android', 'darwin'];",
19
+ 'const T = platform.includes(process.platform);',
20
+ 'const reg = T ? /^file:\\/\\// : /^file:\\/\\/\\//;',
21
+ "return new URL(path, basePath).href.replace(reg, '');",
22
+ '};',
23
+ `const fileUrl = createUrl(import.meta.url, '${convertPath(relativePath)}');`,
24
+ 'export default fileUrl;'
25
+ ].join('\n');
26
+ return contents;
27
+ };
28
+ const getRandomName = (str) => {
29
+ // 使用 MD5 算法创建哈希对象
30
+ const hash = crypto.createHash('md5');
31
+ // 更新哈希对象内容
32
+ hash.update(str);
33
+ return hash.digest('hex');
34
+ };
35
+ const chache = {};
36
+ /**
37
+ *
38
+ * @param fileUrl
39
+ * @returns
40
+ */
41
+ const generateCSSModuleContent = (pathURL) => {
42
+ const fileName = getRandomName(pathURL);
43
+ const outputFileURL = convertPath(join(process.cwd(), 'node_modules', 'lvyjs', 'assets', `${fileName}.css`));
44
+ if (!chache[pathURL]) {
45
+ global.lvyWorkerProt.postMessage({
46
+ type: 'CSS_MODULE_GENERATED',
47
+ payload: {
48
+ from: pathURL,
49
+ to: outputFileURL
50
+ }
51
+ });
52
+ chache[pathURL] = true;
53
+ }
54
+ return `export default "${outputFileURL}";`;
55
+ };
56
+
57
+ export { generateCSSModuleContent, generateModuleContent };
package/lib/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { Options, defineConfig, getOptions, initConfig, usePlugin } from './store.js';
2
+ export { buildAndRun, buildJS } from './rullup/index.js';
3
+ export { ESBuild } from './esbuild/index.js';
package/lib/index.js ADDED
@@ -0,0 +1,44 @@
1
+ import { buildAndRun } from './rullup/index.js';
2
+ export { buildJS } from './rullup/index.js';
3
+ import { initConfig } from './store.js';
4
+ export { defineConfig, getOptions, usePlugin } from './store.js';
5
+ export { ESBuild } from './esbuild/index.js';
6
+
7
+ /**
8
+ * @param input
9
+ */
10
+ const onDev = async () => {
11
+ const apps = [];
12
+ if (Array.isArray(global.lvyConfig?.plugins)) {
13
+ // 修改config
14
+ for (const plugin of global.lvyConfig.plugins) {
15
+ if (!plugin) {
16
+ continue;
17
+ }
18
+ apps.push(plugin(global.lvyConfig));
19
+ }
20
+ }
21
+ // 执行loader
22
+ await import('./main.js');
23
+ //
24
+ for (const app of apps) {
25
+ if (!app) {
26
+ continue;
27
+ }
28
+ if (typeof app == 'function')
29
+ app(global.lvyConfig);
30
+ }
31
+ };
32
+ const main = async () => {
33
+ if (process.argv.includes('--lvy-dev')) {
34
+ await initConfig();
35
+ onDev();
36
+ }
37
+ else if (process.argv.includes('--lvy-build')) {
38
+ await initConfig();
39
+ buildAndRun();
40
+ }
41
+ };
42
+ main();
43
+
44
+ export { buildAndRun, initConfig };
@@ -0,0 +1,18 @@
1
+ import { MessagePort } from 'worker_threads';
2
+
3
+ declare global {
4
+ var lvyWorkerProt: MessagePort;
5
+ }
6
+ declare function initialize({ port, lvyConfig }: {
7
+ port: any;
8
+ lvyConfig: any;
9
+ }): Promise<void>;
10
+ /**
11
+ * @param url
12
+ * @param context
13
+ * @param defaultLoad
14
+ * @returns
15
+ */
16
+ declare const load: (url: any, context: any, defaultLoad: any) => Promise<any>;
17
+
18
+ export { initialize, load };
package/lib/loader.js ADDED
@@ -0,0 +1,31 @@
1
+ import { ESBuild } from './esbuild/index.js';
2
+
3
+ const platform = ['win32'].includes(process.platform);
4
+ const reg = platform ? /^file:\/\/\// : /^file:\/\//;
5
+ const nodeReg = /(node_modules|node_|node:)/;
6
+ const jsReg = /\.(js|ts|jsx|tsx)$/;
7
+ async function initialize({ port, lvyConfig }) {
8
+ global.lvyConfig = lvyConfig;
9
+ global.lvyWorkerProt = port;
10
+ }
11
+ /**
12
+ * @param url
13
+ * @param context
14
+ * @param defaultLoad
15
+ * @returns
16
+ */
17
+ const load = async (url, context, defaultLoad) => {
18
+ if (nodeReg.test(url)) {
19
+ return defaultLoad(url, context);
20
+ }
21
+ if (!jsReg.test(url)) {
22
+ return defaultLoad(url, context);
23
+ }
24
+ const code = await ESBuild(url.replace(reg, ''));
25
+ return defaultLoad(url, {
26
+ format: 'module',
27
+ source: code
28
+ });
29
+ };
30
+
31
+ export { initialize, load };
package/lib/main.js ADDED
@@ -0,0 +1,32 @@
1
+ import module from 'node:module';
2
+ import { MessageChannel } from 'node:worker_threads';
3
+ import { postCSS } from './postcss.js';
4
+
5
+ if (!module.register) {
6
+ throw new Error(`This version of Node.js (${process.version}) does not support module.register(). Please upgrade to Node v18.19 or v20.6 and above.`);
7
+ }
8
+ const { port1, port2 } = new MessageChannel();
9
+ const cache = {};
10
+ port1.on('message', msg => {
11
+ if (msg.type == 'CSS_MODULE_GENERATED') {
12
+ const { from, to } = msg.payload;
13
+ if (!cache[from]) {
14
+ postCSS(from, to);
15
+ cache[from] = true;
16
+ }
17
+ }
18
+ else if (msg.type == 'JS_MODULE_GENERATED') ;
19
+ });
20
+ // port1.unref()
21
+ module.register('./loader.js', {
22
+ parentURL: import.meta.url,
23
+ data: {
24
+ port: port2,
25
+ lvyConfig: {
26
+ alias: global.lvyConfig.alias,
27
+ assets: global.lvyConfig.assets,
28
+ styles: global.lvyConfig.styles
29
+ }
30
+ },
31
+ transferList: [port2]
32
+ });
package/lib/postcss.js ADDED
@@ -0,0 +1,168 @@
1
+ import fs from 'fs';
2
+ import postcss from 'postcss';
3
+ import { createRequire } from 'module';
4
+ import { join, resolve, dirname } from 'path';
5
+
6
+ const require = createRequire(import.meta.url);
7
+ const config = {
8
+ css: null,
9
+ sass: null,
10
+ less: null,
11
+ scss: null
12
+ };
13
+ const loadPostcssConfig = (configPath, typing) => {
14
+ if (config[typing]) {
15
+ return {
16
+ plugins: config[typing]
17
+ };
18
+ }
19
+ const plugins = [];
20
+ let aliasEntries = [];
21
+ if (typeof global.lvyConfig?.alias != 'boolean') {
22
+ aliasEntries = global.lvyConfig.alias?.entries || [];
23
+ }
24
+ const includeKeys = ['postcss-import', 'postcss-url', 'autoprefixer'];
25
+ //
26
+ if (aliasEntries.length > 0) {
27
+ // 创建 postcss-import 插件并配置别名解析
28
+ try {
29
+ plugins.push(require('postcss-import')({
30
+ resolve: (id, basedir) => {
31
+ // 检查别名
32
+ for (const entry of aliasEntries) {
33
+ if (id.startsWith(entry.find)) {
34
+ const aliasedPath = id.replace(entry.find, entry.replacement);
35
+ return resolve(basedir, aliasedPath); // 返回绝对路径
36
+ }
37
+ }
38
+ return id; // 默认返回原始路径
39
+ }
40
+ }));
41
+ }
42
+ catch (err) {
43
+ console.error(err);
44
+ }
45
+ try {
46
+ plugins.push(require('postcss-url')({
47
+ url: asset => {
48
+ // 使用 resolve 逻辑处理 URL
49
+ for (const entry of aliasEntries) {
50
+ if (asset.url.startsWith(entry.find)) {
51
+ const aliasedPath = asset.url.replace(entry.find, entry.replacement);
52
+ return aliasedPath; // 返回解析后的 URL
53
+ }
54
+ }
55
+ return asset.url; // 返回原始路径
56
+ }
57
+ }));
58
+ }
59
+ catch (err) {
60
+ console.error(err);
61
+ }
62
+ }
63
+ for (let i = 2; i < includeKeys.length; i++) {
64
+ plugins.push(require(includeKeys[i])({}));
65
+ }
66
+ try {
67
+ if (fs.existsSync(configPath)) {
68
+ const cfg = require(configPath);
69
+ // 添加其他插件
70
+ if (!Array.isArray(cfg.plugins)) {
71
+ const keys = Object.keys(cfg.plugins);
72
+ for (const key of keys) {
73
+ try {
74
+ if (includeKeys.includes(key))
75
+ continue;
76
+ const pluginConfig = cfg.plugins[key];
77
+ const plugin = require(key);
78
+ if (typeof plugin === 'function') {
79
+ plugins.push(plugin(pluginConfig));
80
+ }
81
+ else {
82
+ throw new Error(`插件 ${key} 不是有效的 PostCSS 插件函数`);
83
+ }
84
+ }
85
+ catch (err) {
86
+ console.error(`加载 PostCSS 插件 ${key} 失败:`, err);
87
+ }
88
+ }
89
+ }
90
+ else {
91
+ plugins.push(...cfg.plugins);
92
+ }
93
+ }
94
+ }
95
+ catch (err) {
96
+ console.error('加载 PostCSS 配置失败:', err);
97
+ }
98
+ config[typing] = plugins;
99
+ return {
100
+ plugins: config[typing]
101
+ };
102
+ };
103
+ const postCSS = (inputPath, outputPath) => {
104
+ const configPath = join(process.cwd(), 'postcss.config.cjs');
105
+ let typing = 'css';
106
+ let parser = undefined;
107
+ if (/\.sass$/.test(inputPath)) {
108
+ typing = 'sass';
109
+ // parser = require('postcss-sass')
110
+ }
111
+ else if (/\.less$/.test(inputPath)) {
112
+ typing = 'less';
113
+ // parser = require('postcss-less')
114
+ }
115
+ else if (/\.scss$/.test(inputPath)) {
116
+ typing = 'scss';
117
+ // parser = require('postcss-scss')
118
+ }
119
+ const postcssConfig = loadPostcssConfig(configPath, 'css');
120
+ if (!postcssConfig)
121
+ return;
122
+ const readAndProcessCSS = async () => {
123
+ let css = '';
124
+ if (typing === 'less') {
125
+ const less = require('less');
126
+ const lessResult = await less.render(fs.readFileSync(inputPath, 'utf-8'));
127
+ css = lessResult.css;
128
+ }
129
+ else if (typing === 'sass' || typing === 'scss') {
130
+ const sass = require('sass');
131
+ const sassResult = sass.renderSync({ file: inputPath });
132
+ css = sassResult.css.toString();
133
+ }
134
+ else {
135
+ css = fs.readFileSync(inputPath, 'utf-8');
136
+ }
137
+ fs.mkdirSync(dirname(outputPath), { recursive: true });
138
+ const result = await postcss(postcssConfig.plugins).process(css, {
139
+ parser: parser,
140
+ from: inputPath,
141
+ to: outputPath
142
+ });
143
+ fs.writeFileSync(outputPath, result.css);
144
+ if (result.warnings().length) {
145
+ result.warnings().forEach(warn => {
146
+ console.warn(warn.toString());
147
+ });
148
+ }
149
+ const dependencies = result.messages
150
+ .filter(msg => msg.type === 'dependency')
151
+ .map(msg => msg.file);
152
+ for (const dep of dependencies) {
153
+ fs.watch(dep, eventType => {
154
+ if (eventType === 'change') {
155
+ readAndProcessCSS();
156
+ }
157
+ });
158
+ }
159
+ };
160
+ readAndProcessCSS();
161
+ fs.watch(inputPath, eventType => {
162
+ if (eventType === 'change') {
163
+ readAndProcessCSS();
164
+ }
165
+ });
166
+ };
167
+
168
+ export { postCSS };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 打包 JS
3
+ * *** 注意 **
4
+ * 和initConfig配合使用
5
+ * **
6
+ * 确保已经初始化了配置
7
+ * @param inputs
8
+ * @param output
9
+ */
10
+ declare const buildJS: (inputs: string[]) => Promise<void>;
11
+ /**
12
+ *
13
+ * @param script
14
+ */
15
+ declare function buildAndRun(): Promise<void>;
16
+
17
+ export { buildAndRun, buildJS };
@@ -0,0 +1,135 @@
1
+ import { rollup } from 'rollup';
2
+ import { join } from 'path';
3
+ import typescript from '@rollup/plugin-typescript';
4
+ import commonjs from '@rollup/plugin-commonjs';
5
+ import json from '@rollup/plugin-json';
6
+ import styles from 'rollup-plugin-styles';
7
+ import { getScriptFiles } from './utils/files.js';
8
+ import alias from '@rollup/plugin-alias';
9
+ import { rollupStylesCSSImport } from './plugins/loader-css.js';
10
+ import { rollupAssets } from './plugins/loader-files.js';
11
+
12
+ /**
13
+ * 用于忽略警告
14
+ * @param warning
15
+ * @param warn
16
+ */
17
+ const onwarn = (warning, warn) => {
18
+ if (warning.code === 'UNRESOLVED_IMPORT')
19
+ return;
20
+ warn(warning);
21
+ };
22
+ /**
23
+ * 打包 JS
24
+ * *** 注意 **
25
+ * 和initConfig配合使用
26
+ * **
27
+ * 确保已经初始化了配置
28
+ * @param inputs
29
+ * @param output
30
+ */
31
+ const buildJS = async (inputs) => {
32
+ if (!global.lvyConfig)
33
+ global.lvyConfig = {};
34
+ if (!global.lvyConfig.build)
35
+ global.lvyConfig.build = {};
36
+ // 插件
37
+ const plugins = [];
38
+ if (typeof global.lvyConfig?.alias !== 'boolean') {
39
+ plugins.push(alias(global.lvyConfig?.alias ?? {}));
40
+ }
41
+ if (typeof global.lvyConfig?.assets !== 'boolean') {
42
+ plugins.push(rollupAssets(global.lvyConfig?.assets ?? {}));
43
+ }
44
+ if (typeof global.lvyConfig?.styles !== 'boolean') {
45
+ if (!global.lvyConfig.alias)
46
+ global.lvyConfig.alias = {};
47
+ const newAlias = val => {
48
+ const alias = {};
49
+ // 遍历 entries 数组
50
+ val.entries.forEach(entry => {
51
+ alias[entry.find] = entry.replacement;
52
+ });
53
+ return alias;
54
+ };
55
+ plugins.push(styles({
56
+ alias: newAlias(global.lvyConfig?.alias),
57
+ mode: ['inject', () => '']
58
+ }));
59
+ plugins.push(rollupStylesCSSImport(global.lvyConfig.styles));
60
+ }
61
+ plugins.push(json());
62
+ if (typeof global.lvyConfig.build != 'boolean') {
63
+ //
64
+ for (const key in global.lvyConfig.build) {
65
+ if (typeof global.lvyConfig.build[key] == 'boolean') {
66
+ continue;
67
+ }
68
+ if (key == 'commonjs' && !global.lvyConfig.build['@rollup/plugin-commonjs']) {
69
+ plugins.push(commonjs(global.lvyConfig.build[key]));
70
+ }
71
+ else if (key == 'typescript' && !global.lvyConfig.build['@rollup/plugin-typescript']) {
72
+ plugins.push(typescript(global.lvyConfig.build[key]));
73
+ }
74
+ else if (key == 'OutputOptions') {
75
+ continue;
76
+ }
77
+ else if (key == 'RollupOptions') {
78
+ continue;
79
+ }
80
+ }
81
+ // 如果不存在这些配置
82
+ const keys = ['commonjs', 'typescript'];
83
+ for (const key of keys) {
84
+ // 如果是布尔值
85
+ if (typeof global.lvyConfig.build[key] == 'boolean') {
86
+ continue;
87
+ }
88
+ // 存在这些配置
89
+ if (global.lvyConfig.build[key]) {
90
+ continue;
91
+ }
92
+ //
93
+ if (key === 'commonjs') {
94
+ plugins.push(commonjs());
95
+ }
96
+ else if (key === 'typescript') {
97
+ plugins.push(typescript());
98
+ }
99
+ }
100
+ }
101
+ const RollupOptions = global.lvyConfig?.build?.RollupOptions ?? {};
102
+ const OutputOptions = global.lvyConfig?.build?.OutputOptions ?? [];
103
+ // build
104
+ const bundle = await rollup({
105
+ input: inputs,
106
+ plugins: [...plugins],
107
+ onwarn: onwarn,
108
+ ...RollupOptions
109
+ });
110
+ // 写入输出文件
111
+ await bundle.write({
112
+ dir: 'lib',
113
+ format: 'es',
114
+ sourcemap: false,
115
+ preserveModules: true,
116
+ assetFileNames: 'assets/[name]-[hash][extname]',
117
+ ...OutputOptions
118
+ });
119
+ };
120
+ /**
121
+ *
122
+ * @param script
123
+ */
124
+ async function buildAndRun() {
125
+ if (!global.lvyConfig)
126
+ global.lvyConfig = {};
127
+ if (!global.lvyConfig.build)
128
+ global.lvyConfig.build = {};
129
+ // rollup 配置
130
+ let inputDir = global.lvyConfig?.build?.OutputOptions?.input ?? 'src';
131
+ const inputFiles = getScriptFiles(join(process.cwd(), inputDir));
132
+ await buildJS(inputFiles);
133
+ }
134
+
135
+ export { buildAndRun, buildJS };
@@ -0,0 +1,4 @@
1
+ const assetsReg = /\.(png|jpg|jpeg|gif|svg|webp|ico)$/
2
+ const cssReg = /\.(css|scss|less|sass|less)$/
3
+
4
+ export { assetsReg, cssReg }
@@ -0,0 +1,60 @@
1
+ import { createFilter } from '@rollup/pluginutils';
2
+ import { resolve, dirname, basename } from 'node:path';
3
+ import { cssReg } from '../../config.js';
4
+
5
+ /**
6
+ *
7
+ * @returns
8
+ */
9
+ const rollupStylesCSSImport = (options) => {
10
+ const include = options?.filter ?? cssReg;
11
+ const filter = createFilter(include, null);
12
+ return {
13
+ name: 'c-css',
14
+ resolveId(source, importer) {
15
+ if (filter(source) && importer) {
16
+ return resolve(dirname(importer), source);
17
+ }
18
+ },
19
+ load(id) {
20
+ if (filter(id))
21
+ this.addWatchFile(resolve(id));
22
+ return null;
23
+ },
24
+ async transform(code, id) {
25
+ if (!filter(id))
26
+ return null;
27
+ // 删除 export default css
28
+ const codex = code.replace(/(export|default css)/g, '');
29
+ // 使用 eval 执行代码并获取默认导出的值
30
+ const evalCode = `
31
+ (() => {
32
+ ${codex}
33
+ return css;
34
+ })()
35
+ `;
36
+ // 得到css变量的值
37
+ const csscode = eval(evalCode);
38
+ // 确保最后生产的css文件
39
+ const refeId = this.emitFile({
40
+ // 属于静态资源
41
+ type: 'asset',
42
+ name: basename(`${id}.css`),
43
+ // 内容
44
+ source: csscode
45
+ });
46
+ const contents = `
47
+ const createUrl = () => {
48
+ const platform = ['linux', 'android', 'darwin'];
49
+ const T = platform.includes(process.platform);
50
+ const reg = T ? /^file:\\/\\// : /^file:\\/\\/\\//
51
+ return import.meta.ROLLUP_FILE_URL_${refeId}.replace(reg, '')
52
+ };
53
+ export default createUrl();
54
+ `;
55
+ return contents;
56
+ }
57
+ };
58
+ };
59
+
60
+ export { rollupStylesCSSImport };
@@ -0,0 +1,40 @@
1
+ import { resolve, dirname, basename } from 'path';
2
+ import { readFileSync } from 'fs';
3
+ import { assetsReg } from '../../config.js';
4
+
5
+ /**
6
+ * @param {Object} options
7
+ * @returns {Object}
8
+ */
9
+ const rollupAssets = (options) => {
10
+ const { filter = assetsReg } = options ?? {};
11
+ return {
12
+ name: 'rollup-node-files',
13
+ resolveId(source, importer) {
14
+ if (filter.test(source) && importer) {
15
+ return resolve(dirname(importer), source);
16
+ }
17
+ },
18
+ load(id) {
19
+ if (filter.test(id)) {
20
+ const referenceId = this.emitFile({
21
+ type: 'asset',
22
+ name: basename(id),
23
+ source: readFileSync(id)
24
+ });
25
+ const content = [
26
+ 'const createUrl = () => {',
27
+ "const platform = ['linux', 'android', 'darwin'];",
28
+ 'const T = platform.includes(process.platform);',
29
+ 'const reg = T ? /^file:\\/\\// : /^file:\\/\\/\\//',
30
+ 'return import.meta.ROLLUP_FILE_URL_' + referenceId + ".replace(reg, '')",
31
+ '};',
32
+ 'export default createUrl();'
33
+ ].join('\n');
34
+ return content;
35
+ }
36
+ }
37
+ };
38
+ };
39
+
40
+ export { rollupAssets };
@@ -0,0 +1,26 @@
1
+ import { join } from 'path';
2
+ import { readdirSync } from 'fs';
3
+
4
+ /**
5
+ * 获取指定目录下的所有 ts、js、jsx、tsx 文件
6
+ * @param dir 目录路径
7
+ * @returns 文件路径数组
8
+ */
9
+ const getScriptFiles = (dir) => {
10
+ const results = [];
11
+ const list = readdirSync(dir, { withFileTypes: true });
12
+ list.forEach(item => {
13
+ const fullPath = join(dir, item.name);
14
+ if (item.isDirectory()) {
15
+ results.push(...getScriptFiles(fullPath));
16
+ }
17
+ else if (item.isFile() &&
18
+ /\.(ts|js|jsx|tsx)$/.test(item.name) &&
19
+ !item.name.endsWith('.d.ts')) {
20
+ results.push(fullPath);
21
+ }
22
+ });
23
+ return results;
24
+ };
25
+
26
+ export { getScriptFiles };
package/lib/store.d.ts ADDED
@@ -0,0 +1,101 @@
1
+ import { RollupCommonJSOptions } from '@rollup/plugin-commonjs';
2
+ import { RollupTypescriptOptions } from '@rollup/plugin-typescript';
3
+ import { SameShape, BuildOptions } from 'esbuild';
4
+ import { RollupOptions, OutputOptions } from 'rollup';
5
+
6
+ interface Alias {
7
+ find: string | RegExp;
8
+ replacement: string;
9
+ }
10
+ type Options = {
11
+ /**
12
+ * 配置调整机及其回调插件
13
+ */
14
+ plugins?: ((options: Options) => ((options: Options) => void) | void | undefined | null)[];
15
+ /**
16
+ * 别名
17
+ */
18
+ alias?: {
19
+ /**
20
+ * 别名规则
21
+ */
22
+ entries?: Alias[];
23
+ } | false;
24
+ /**
25
+ * 静态资源识别
26
+ */
27
+ assets?: {
28
+ /**
29
+ * 过滤得到指定格式的文件识别之为静态资源
30
+ */
31
+ filter?: RegExp;
32
+ } | false;
33
+ styles?: {
34
+ /**
35
+ * 过滤得到指定格式的文件识别之为静态资源
36
+ */
37
+ filter?: RegExp;
38
+ } | false;
39
+ /**
40
+ * 运行时配置
41
+ */
42
+ esbuild?: {
43
+ /**
44
+ *
45
+ */
46
+ options?: SameShape<BuildOptions, BuildOptions>;
47
+ };
48
+ /**
49
+ * 打包时配置
50
+ */
51
+ build?: {
52
+ /**
53
+ * cjs文件处理
54
+ */
55
+ commonjs?: RollupCommonJSOptions | false;
56
+ /**
57
+ * ts配置
58
+ */
59
+ typescript?: RollupTypescriptOptions | false;
60
+ /**
61
+ *
62
+ */
63
+ RollupOptions?: RollupOptions;
64
+ /**
65
+ *
66
+ */
67
+ OutputOptions?: OutputOptions & {
68
+ /**
69
+ * 默认 src
70
+ */
71
+ input?: string;
72
+ };
73
+ } | false;
74
+ };
75
+ /**
76
+ *
77
+ * @param options
78
+ * @returns
79
+ */
80
+ declare const usePlugin: (load: (options: Options) => ((options: Options) => void) | void | undefined | null) => (options: Options) => ((options: Options) => void) | void | undefined | null;
81
+ /**
82
+ *
83
+ */
84
+ declare global {
85
+ var lvyConfig: Options;
86
+ }
87
+ /**
88
+ *
89
+ */
90
+ declare const initConfig: () => Promise<void>;
91
+ /**
92
+ * @returns
93
+ */
94
+ declare const getOptions: () => Options;
95
+ /**
96
+ * @param param0
97
+ * @returns
98
+ */
99
+ declare const defineConfig: (optoins?: Options) => Options | undefined;
100
+
101
+ export { type Options, defineConfig, getOptions, initConfig, usePlugin };
package/lib/store.js ADDED
@@ -0,0 +1,47 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
3
+
4
+ /**
5
+ *
6
+ * @param options
7
+ * @returns
8
+ */
9
+ const usePlugin = (load) => load;
10
+ /**
11
+ *
12
+ */
13
+ const initConfig = async () => {
14
+ if (!global.lvyConfig)
15
+ global.lvyConfig = {};
16
+ const files = [
17
+ 'lvy.config.ts',
18
+ 'lvy.config.js',
19
+ 'lvy.config.mjs',
20
+ 'lvy.config.cjs',
21
+ 'lvy.config.tsx'
22
+ ];
23
+ let configDir = '';
24
+ for (const file of files) {
25
+ if (existsSync(file)) {
26
+ configDir = file;
27
+ break;
28
+ }
29
+ }
30
+ if (configDir !== '') {
31
+ const v = await import(`file://${join(process.cwd(), configDir)}`);
32
+ if (v?.default) {
33
+ global.lvyConfig = v.default;
34
+ }
35
+ }
36
+ };
37
+ /**
38
+ * @returns
39
+ */
40
+ const getOptions = () => global.lvyConfig;
41
+ /**
42
+ * @param param0
43
+ * @returns
44
+ */
45
+ const defineConfig = (optoins) => optoins;
46
+
47
+ export { defineConfig, getOptions, initConfig, usePlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lvyjs",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "tsx compile script",
5
5
  "author": "lemonade",
6
6
  "license": "MIT",