@lowdefy/build 4.7.2 → 5.0.0
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/dist/build/addDefaultPages/404.js +8 -2
- package/dist/build/buildApi/buildRoutine/validateStep.js +7 -5
- package/dist/build/buildApi/validateEndpoint.js +6 -5
- package/dist/build/buildConnections.js +6 -0
- package/dist/build/buildImports/buildIconImports.js +5 -1
- package/dist/build/buildImports/buildImportsDev.js +1 -6
- package/dist/build/buildImports/buildImportsProd.js +1 -6
- package/dist/build/buildImports/validateIconImports.js +65 -0
- package/dist/build/buildJs/jsMapParser.js +5 -2
- package/dist/build/buildPages/buildBlock/buildBlock.js +12 -4
- package/dist/build/buildPages/buildBlock/buildEvents.js +34 -1
- package/dist/build/buildPages/buildBlock/buildRequests.js +7 -5
- package/dist/build/buildPages/buildBlock/buildSubBlocks.js +9 -9
- package/dist/build/buildPages/buildBlock/countBlockOperators.js +1 -1
- package/dist/build/buildPages/buildBlock/moveAreasToSlots.js +31 -0
- package/dist/build/buildPages/buildBlock/{moveSkeletonBlocksToArea.js → moveSkeletonBlocksToSlot.js} +8 -8
- package/dist/build/buildPages/buildBlock/{moveSubBlocksToArea.js → moveSubBlocksToSlot.js} +3 -3
- package/dist/build/buildPages/buildBlock/normalizeClassAndStyles.js +124 -0
- package/dist/build/buildPages/buildBlock/normalizeLayout.js +68 -0
- package/dist/build/buildPages/buildBlock/setBlockId.js +7 -1
- package/dist/build/buildPages/buildBlock/validateSlots.js +34 -0
- package/dist/build/buildPages/buildPage.js +23 -1
- package/dist/build/buildRefs/addLineNumbers.js +76 -0
- package/dist/build/{buildImports/buildStyleImports.js → buildRefs/getLineNumber.js} +4 -10
- package/dist/build/buildRefs/getRefContent.js +9 -1
- package/dist/build/buildRefs/parseRefContent.js +4 -66
- package/dist/build/buildTypes.js +4 -2
- package/dist/build/cleanBuildDirectory.js +3 -1
- package/dist/build/collectPageContent.js +57 -0
- package/dist/build/jit/buildPageJit.js +14 -3
- package/dist/build/jit/collectSkeletonSourceFiles.js +75 -0
- package/dist/build/jit/extractIconData.js +16 -1
- package/dist/build/jit/pageContentKeys.js +1 -0
- package/dist/build/jit/shallowBuild.js +34 -1
- package/dist/build/jit/stripPageContent.js +29 -0
- package/dist/build/jit/writePageJit.js +9 -1
- package/dist/build/testSchema.js +3 -0
- package/dist/build/writePluginImports/collectBlockSourceContent.js +65 -0
- package/dist/build/writePluginImports/writeActionSchemaMap.js +1 -1
- package/dist/build/writePluginImports/writeBlockSchemaMap.js +45 -7
- package/dist/build/writePluginImports/writeGlobalsCss.js +126 -0
- package/dist/build/writePluginImports/writeOperatorSchemaMap.js +1 -1
- package/dist/build/writePluginImports/writePluginImports.js +7 -2
- package/dist/build/writeTheme.js +28 -0
- package/dist/createContext.js +2 -0
- package/dist/defaultTypesMap.js +1693 -837
- package/dist/index.js +16 -0
- package/dist/lowdefySchema.js +100 -0
- package/dist/scripts/generateDefaultTypes.js +5 -10
- package/dist/test-utils/runBuild.js +3 -0
- package/dist/test-utils/runBuildForSnapshots.js +5 -2
- package/dist/test-utils/testContext.js +2 -1
- package/dist/utils/createHandleWarning.js +3 -0
- package/dist/utils/createPluginTypesMap.js +5 -9
- package/dist/utils/validateId.js +24 -0
- package/package.json +47 -47
- package/dist/build/writePluginImports/writeStyleImports.js +0 -34
|
@@ -40,6 +40,7 @@ import writeApi from '../writeApi.js';
|
|
|
40
40
|
import writeGlobal from '../writeGlobal.js';
|
|
41
41
|
import writeJs from '../buildJs/writeJs.js';
|
|
42
42
|
import writeLogger from '../writeLogger.js';
|
|
43
|
+
import writeTheme from '../writeTheme.js';
|
|
43
44
|
import writeMaps from '../writeMaps.js';
|
|
44
45
|
import updateServerPackageJson from '../full/updateServerPackageJson.js';
|
|
45
46
|
import writeMenus from '../writeMenus.js';
|
|
@@ -48,6 +49,9 @@ import writePluginImports from '../writePluginImports/writePluginImports.js';
|
|
|
48
49
|
import addInstalledTypes from './addInstalledTypes.js';
|
|
49
50
|
import buildJsShallow from './buildJsShallow.js';
|
|
50
51
|
import buildShallowPages from './buildShallowPages.js';
|
|
52
|
+
import collectPageContent from '../collectPageContent.js';
|
|
53
|
+
import collectSkeletonSourceFiles from './collectSkeletonSourceFiles.js';
|
|
54
|
+
import stripPageContent from './stripPageContent.js';
|
|
51
55
|
import writeSourcelessPages from './writeSourcelessPages.js';
|
|
52
56
|
async function shallowBuild(options) {
|
|
53
57
|
makeId.reset();
|
|
@@ -67,11 +71,33 @@ async function shallowBuild(options) {
|
|
|
67
71
|
}
|
|
68
72
|
throw err;
|
|
69
73
|
}
|
|
74
|
+
// Stop early if buildRefs collected errors (e.g., YAML parse errors).
|
|
75
|
+
// Failed _ref resolutions leave null entries in arrays — logging now
|
|
76
|
+
// surfaces the real error before downstream code crashes on nulls.
|
|
77
|
+
logCollectedErrors(context);
|
|
78
|
+
// Collect skeleton source files while ~r markers still exist on objects.
|
|
79
|
+
const skeletonSourceFiles = collectSkeletonSourceFiles({
|
|
80
|
+
components,
|
|
81
|
+
context
|
|
82
|
+
});
|
|
70
83
|
// addKeys + testSchema first for error location info
|
|
71
84
|
tryBuildStep(addKeys, 'addKeys', {
|
|
72
85
|
components,
|
|
73
86
|
context
|
|
74
87
|
});
|
|
88
|
+
context.tailwindContentMap = new Map();
|
|
89
|
+
for (const page of components.pages ?? []){
|
|
90
|
+
const content = collectPageContent([
|
|
91
|
+
page
|
|
92
|
+
]);
|
|
93
|
+
if (content) {
|
|
94
|
+
context.tailwindContentMap.set(page.id, content);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
stripPageContent({
|
|
98
|
+
components,
|
|
99
|
+
context
|
|
100
|
+
});
|
|
75
101
|
tryBuildStep(testSchema, 'testSchema', {
|
|
76
102
|
components,
|
|
77
103
|
context
|
|
@@ -179,6 +205,10 @@ async function shallowBuild(options) {
|
|
|
179
205
|
components,
|
|
180
206
|
context
|
|
181
207
|
});
|
|
208
|
+
await writeTheme({
|
|
209
|
+
components,
|
|
210
|
+
context
|
|
211
|
+
});
|
|
182
212
|
await writeLogger({
|
|
183
213
|
components,
|
|
184
214
|
context
|
|
@@ -188,7 +218,10 @@ async function shallowBuild(options) {
|
|
|
188
218
|
});
|
|
189
219
|
await context.writeBuildArtifact('connectionIds.json', JSON.stringify([
|
|
190
220
|
...context.connectionIds
|
|
191
|
-
]));
|
|
221
|
+
].sort()));
|
|
222
|
+
await context.writeBuildArtifact('skeletonSourceFiles.json', JSON.stringify([
|
|
223
|
+
...skeletonSourceFiles
|
|
224
|
+
].sort()));
|
|
192
225
|
await writeMenus({
|
|
193
226
|
components,
|
|
194
227
|
context
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { type } from '@lowdefy/helpers';
|
|
16
|
+
import PAGE_CONTENT_KEYS from './pageContentKeys.js';
|
|
17
|
+
function stripPageContent({ components, context }) {
|
|
18
|
+
for (const page of components.pages ?? []){
|
|
19
|
+
// Only strip pages that have a source ref (will be JIT-rebuilt).
|
|
20
|
+
// Inline pages (no ~r) must keep their content for buildShallowPages.
|
|
21
|
+
const keyMapEntry = context.keyMap[page['~k']];
|
|
22
|
+
const refId = keyMapEntry?.['~r'] ?? null;
|
|
23
|
+
if (type.isNone(refId)) continue;
|
|
24
|
+
for (const key of PAGE_CONTENT_KEYS){
|
|
25
|
+
delete page[key];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export default stripPageContent;
|
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/ import
|
|
15
|
+
*/ import path from 'path';
|
|
16
|
+
import { serializer, type } from '@lowdefy/helpers';
|
|
17
|
+
import { writeFile } from '@lowdefy/node-utils';
|
|
18
|
+
import collectPageContent from '../collectPageContent.js';
|
|
16
19
|
import writeJs from '../buildJs/writeJs.js';
|
|
17
20
|
async function writePageJit({ page, context }) {
|
|
18
21
|
// Write page JSON
|
|
@@ -40,5 +43,10 @@ async function writePageJit({ page, context }) {
|
|
|
40
43
|
await writeJs({
|
|
41
44
|
context
|
|
42
45
|
});
|
|
46
|
+
// Write per-page content file for Tailwind to scan class and property strings
|
|
47
|
+
const pageContent = collectPageContent([
|
|
48
|
+
page
|
|
49
|
+
]);
|
|
50
|
+
await writeFile(path.join(context.directories.server, 'lowdefy-build', 'tailwind', `${page.pageId}.html`), '<!-- Generated by Lowdefy build -->\n' + (pageContent ?? ''));
|
|
43
51
|
}
|
|
44
52
|
export default writePageJit;
|
package/dist/build/testSchema.js
CHANGED
|
@@ -48,9 +48,12 @@ function testSchema({ components, context }) {
|
|
|
48
48
|
components,
|
|
49
49
|
instancePath
|
|
50
50
|
});
|
|
51
|
+
const propertyName = instancePath[instancePath.length - 1];
|
|
51
52
|
let message = error.message;
|
|
52
53
|
if (error.params?.additionalProperty) {
|
|
53
54
|
message = `${message} - "${error.params.additionalProperty}"`;
|
|
55
|
+
} else if (propertyName) {
|
|
56
|
+
message = `"${propertyName}" ${message}`;
|
|
54
57
|
}
|
|
55
58
|
const configError = new ConfigError(message, {
|
|
56
59
|
configKey,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import fs from 'fs';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { createRequire } from 'node:module';
|
|
18
|
+
// Extract all string literals from JS source that could be Tailwind class candidates.
|
|
19
|
+
// We read the raw JS text — no AST parsing needed. Tailwind's scanner does the same:
|
|
20
|
+
// it treats every word-like token as a potential class candidate.
|
|
21
|
+
function readJsFiles(distDir) {
|
|
22
|
+
const content = [];
|
|
23
|
+
function walk(dir) {
|
|
24
|
+
for (const entry of fs.readdirSync(dir, {
|
|
25
|
+
withFileTypes: true
|
|
26
|
+
})){
|
|
27
|
+
const fullPath = path.join(dir, entry.name);
|
|
28
|
+
if (entry.isDirectory()) {
|
|
29
|
+
walk(fullPath);
|
|
30
|
+
} else if (/\.(js|jsx|ts|tsx|mjs)$/.test(entry.name)) {
|
|
31
|
+
content.push(fs.readFileSync(fullPath, 'utf8'));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (fs.existsSync(distDir)) {
|
|
36
|
+
walk(distDir);
|
|
37
|
+
}
|
|
38
|
+
return content.join('\n');
|
|
39
|
+
}
|
|
40
|
+
function collectBlockSourceContent({ components, serverDirectory }) {
|
|
41
|
+
// Resolve packages from the server directory, not from @lowdefy/build's own location.
|
|
42
|
+
// In production, @lowdefy/build is installed inside .lowdefy/server/node_modules/.
|
|
43
|
+
// With pnpm, import.meta.url resolves to the .pnpm store where only @lowdefy/build's
|
|
44
|
+
// own declared deps are visible. Block packages are deps of the server, not of
|
|
45
|
+
// @lowdefy/build, so require.resolve from import.meta.url silently fails.
|
|
46
|
+
// Rooting at the server's package.json ensures block packages are always reachable.
|
|
47
|
+
const requireFromServer = createRequire(path.join(serverDirectory, 'package.json'));
|
|
48
|
+
const packages = [
|
|
49
|
+
...new Set((components.imports?.blocks ?? []).map((b)=>b.package))
|
|
50
|
+
];
|
|
51
|
+
const allContent = [];
|
|
52
|
+
for (const packageName of packages){
|
|
53
|
+
try {
|
|
54
|
+
// Resolve the package entry to find its real location on disk.
|
|
55
|
+
// This follows pnpm symlinks, yarn PnP, npm hoisting — any install strategy.
|
|
56
|
+
const entryPath = requireFromServer.resolve(`${packageName}/blocks`);
|
|
57
|
+
const distDir = path.dirname(entryPath);
|
|
58
|
+
allContent.push(readJsFiles(distDir));
|
|
59
|
+
} catch {
|
|
60
|
+
// Package not resolvable from server context (e.g., custom plugin not installed) — skip.
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return allContent.join('\n');
|
|
64
|
+
}
|
|
65
|
+
export default collectBlockSourceContent;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
for (const [packageName, actions] of Object.entries(actionsByPackage)){
|
|
26
26
|
let packageSchemas;
|
|
27
27
|
try {
|
|
28
|
-
packageSchemas = await import(`${packageName}/schemas`);
|
|
28
|
+
packageSchemas = await import(/* webpackIgnore: true */ `${packageName}/schemas`);
|
|
29
29
|
} catch {
|
|
30
30
|
// Package not resolvable from build context (custom plugins) — skip
|
|
31
31
|
}
|
|
@@ -12,8 +12,10 @@
|
|
|
12
12
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
|
-
*/
|
|
15
|
+
*/ import { buildBlockSchema } from '@lowdefy/block-utils';
|
|
16
|
+
async function writeBlockSchemaMap({ components, context }) {
|
|
16
17
|
const schemas = {};
|
|
18
|
+
const allMetas = {};
|
|
17
19
|
const typesMapSchemas = context.typesMap.schemas?.blocks ?? {};
|
|
18
20
|
const blocksByPackage = {};
|
|
19
21
|
for (const block of components.imports.blocks){
|
|
@@ -23,20 +25,56 @@
|
|
|
23
25
|
blocksByPackage[block.package].push(block);
|
|
24
26
|
}
|
|
25
27
|
for (const [packageName, blocks] of Object.entries(blocksByPackage)){
|
|
26
|
-
let
|
|
28
|
+
let packageMetas;
|
|
27
29
|
try {
|
|
28
|
-
|
|
30
|
+
packageMetas = await import(/* webpackIgnore: true */ `${packageName}/metas`);
|
|
29
31
|
} catch {
|
|
30
|
-
|
|
32
|
+
try {
|
|
33
|
+
packageMetas = await import(/* webpackIgnore: true */ `${packageName}/schemas`);
|
|
34
|
+
} catch {
|
|
35
|
+
// Package not resolvable from build context (custom plugins) — skip
|
|
36
|
+
}
|
|
31
37
|
}
|
|
32
38
|
for (const block of blocks){
|
|
39
|
+
const meta = packageMetas?.[block.originalTypeName];
|
|
33
40
|
if (typesMapSchemas[block.typeName]) {
|
|
34
41
|
schemas[block.typeName] = typesMapSchemas[block.typeName];
|
|
35
|
-
} else if (
|
|
36
|
-
schemas[block.typeName] =
|
|
42
|
+
} else if (meta) {
|
|
43
|
+
schemas[block.typeName] = buildBlockSchema(meta);
|
|
44
|
+
}
|
|
45
|
+
if (meta) {
|
|
46
|
+
allMetas[block.typeName] = meta;
|
|
37
47
|
}
|
|
38
48
|
}
|
|
39
49
|
}
|
|
40
|
-
|
|
50
|
+
const blockMetas = {};
|
|
51
|
+
const typesMapBlockMetas = context.typesMap.blockMetas ?? {};
|
|
52
|
+
for (const block of components.imports.blocks){
|
|
53
|
+
const typesMapMeta = typesMapBlockMetas[block.typeName];
|
|
54
|
+
const meta = allMetas[block.typeName];
|
|
55
|
+
if (typesMapMeta) {
|
|
56
|
+
blockMetas[block.typeName] = {
|
|
57
|
+
category: typesMapMeta.category,
|
|
58
|
+
...typesMapMeta.valueType != null && {
|
|
59
|
+
valueType: typesMapMeta.valueType
|
|
60
|
+
},
|
|
61
|
+
...typesMapMeta.initValue !== undefined && {
|
|
62
|
+
initValue: typesMapMeta.initValue
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
} else if (meta) {
|
|
66
|
+
blockMetas[block.typeName] = {
|
|
67
|
+
category: meta.category,
|
|
68
|
+
...meta.valueType != null && {
|
|
69
|
+
valueType: meta.valueType
|
|
70
|
+
},
|
|
71
|
+
...meta.initValue !== undefined && {
|
|
72
|
+
initValue: meta.initValue
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
await context.writeBuildArtifact('plugins/blockSchemas.json', JSON.stringify(schemas));
|
|
78
|
+
await context.writeBuildArtifact('plugins/blockMetas.json', JSON.stringify(blockMetas));
|
|
41
79
|
}
|
|
42
80
|
export default writeBlockSchemaMap;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import fs from 'fs';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { ConfigError } from '@lowdefy/errors';
|
|
18
|
+
import { mergeObjects } from '@lowdefy/helpers';
|
|
19
|
+
import { writeFile } from '@lowdefy/node-utils';
|
|
20
|
+
import collectBlockSourceContent from './collectBlockSourceContent.js';
|
|
21
|
+
const BRIDGE_DEFAULTS = {
|
|
22
|
+
color: {
|
|
23
|
+
primary: 'var(--ant-color-primary)',
|
|
24
|
+
'primary-hover': 'var(--ant-color-primary-hover)',
|
|
25
|
+
'primary-active': 'var(--ant-color-primary-active)',
|
|
26
|
+
'primary-bg': 'var(--ant-color-primary-bg)',
|
|
27
|
+
success: 'var(--ant-color-success)',
|
|
28
|
+
warning: 'var(--ant-color-warning)',
|
|
29
|
+
error: 'var(--ant-color-error)',
|
|
30
|
+
info: 'var(--ant-color-info)',
|
|
31
|
+
'text-primary': 'var(--ant-color-text)',
|
|
32
|
+
'text-secondary': 'var(--ant-color-text-secondary)',
|
|
33
|
+
'bg-container': 'var(--ant-color-bg-container)',
|
|
34
|
+
'bg-layout': 'var(--ant-color-bg-layout)',
|
|
35
|
+
border: 'var(--ant-color-border)'
|
|
36
|
+
},
|
|
37
|
+
radius: {
|
|
38
|
+
DEFAULT: 'var(--ant-border-radius)',
|
|
39
|
+
sm: 'var(--ant-border-radius-sm)',
|
|
40
|
+
lg: 'var(--ant-border-radius-lg)'
|
|
41
|
+
},
|
|
42
|
+
'font-size': {
|
|
43
|
+
DEFAULT: 'var(--ant-font-size)',
|
|
44
|
+
sm: 'var(--ant-font-size-sm)',
|
|
45
|
+
lg: 'var(--ant-font-size-lg)'
|
|
46
|
+
},
|
|
47
|
+
'font-family': {
|
|
48
|
+
sans: 'var(--ant-font-family)'
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
function objectToThemeVars(obj, prefix) {
|
|
52
|
+
const lines = [];
|
|
53
|
+
for (const [key, value] of Object.entries(obj)){
|
|
54
|
+
const varName = prefix ? `${prefix}-${key}` : `--${key}`;
|
|
55
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
56
|
+
lines.push(...objectToThemeVars(value, varName));
|
|
57
|
+
} else {
|
|
58
|
+
lines.push(` ${varName}: ${value};`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return lines;
|
|
62
|
+
}
|
|
63
|
+
function buildThemeVars(tailwindConfig) {
|
|
64
|
+
const merged = mergeObjects([
|
|
65
|
+
{},
|
|
66
|
+
BRIDGE_DEFAULTS,
|
|
67
|
+
tailwindConfig ?? {}
|
|
68
|
+
]);
|
|
69
|
+
return objectToThemeVars(merged).join('\n');
|
|
70
|
+
}
|
|
71
|
+
async function writeGlobalsCss({ components, context }) {
|
|
72
|
+
if (fs.existsSync(path.join(context.directories.config, 'public/styles.less'))) {
|
|
73
|
+
throw new ConfigError('public/styles.less is deprecated. Migrate to: (1) "theme" key in lowdefy.yaml for token overrides (recommended), (2) public/styles.css for custom CSS.');
|
|
74
|
+
}
|
|
75
|
+
const tailwindConfig = components.theme?.tailwind;
|
|
76
|
+
const themeVars = buildThemeVars(tailwindConfig);
|
|
77
|
+
const userStylesAbsolute = path.join(context.directories.config, 'public/styles.css');
|
|
78
|
+
const importUserStyles = fs.existsSync(userStylesAbsolute);
|
|
79
|
+
let userStylesImport = '';
|
|
80
|
+
if (importUserStyles) {
|
|
81
|
+
const relPath = path.relative(context.directories.build, userStylesAbsolute).split(path.sep).join('/');
|
|
82
|
+
userStylesImport = `/* User custom styles */\n@import "${relPath}" layer(components);\n\n`;
|
|
83
|
+
}
|
|
84
|
+
const css = `/* Generated by Lowdefy build */
|
|
85
|
+
|
|
86
|
+
/* Layer order — locks cascade priority before Tailwind declares its own layers */
|
|
87
|
+
@layer theme, base, antd, components, utilities;
|
|
88
|
+
|
|
89
|
+
@import "tailwindcss";
|
|
90
|
+
@import "@lowdefy/layout/grid.css";
|
|
91
|
+
|
|
92
|
+
${userStylesImport}/* Content sources for Tailwind JIT — block JS content collected at build time */
|
|
93
|
+
@source "../lowdefy-build/tailwind/*.html";
|
|
94
|
+
|
|
95
|
+
/* Imported CSS file — when this changes, PostCSS re-runs and Tailwind re-scans @source */
|
|
96
|
+
@import "./tailwind-candidates.css";
|
|
97
|
+
|
|
98
|
+
/* Antd-to-Tailwind theme bridge — extends default Tailwind theme with antd design tokens */
|
|
99
|
+
@theme inline {
|
|
100
|
+
${themeVars}
|
|
101
|
+
}
|
|
102
|
+
`;
|
|
103
|
+
await context.writeBuildArtifact('globals.css', css);
|
|
104
|
+
// Standalone layer order declaration — imported FIRST in _app.js so that
|
|
105
|
+
// Next.js/Turbopack generates a critical CSS chunk that loads before any
|
|
106
|
+
// JavaScript (including antd's CSS-in-JS). This guarantees the cascade
|
|
107
|
+
// layer priority is locked (antd > base/preflight) before antd injects
|
|
108
|
+
// @layer antd {} at runtime. Without this, antd wins the race and becomes
|
|
109
|
+
// the lowest-priority layer.
|
|
110
|
+
await context.writeBuildArtifact('layer-order.css', '/* Generated by Lowdefy build */\n@layer theme, base, antd, components, utilities;\n');
|
|
111
|
+
await context.writeBuildArtifact('tailwind-candidates.css', '/* Generated by Lowdefy build — rewritten on page changes to trigger CSS recompilation */\n');
|
|
112
|
+
for (const [pageId, content] of context.tailwindContentMap ?? []){
|
|
113
|
+
await writeFile(path.join(context.directories.server, 'lowdefy-build', 'tailwind', `${pageId}.html`), '<!-- Generated by Lowdefy build -->\n' + content);
|
|
114
|
+
}
|
|
115
|
+
// Collect Tailwind class candidates from block plugin JS source files.
|
|
116
|
+
// Resolves from the server directory so block packages are reachable regardless
|
|
117
|
+
// of package manager (pnpm strict isolation, yarn PnP, npm hoisting).
|
|
118
|
+
const blockContent = collectBlockSourceContent({
|
|
119
|
+
components,
|
|
120
|
+
serverDirectory: context.directories.server
|
|
121
|
+
});
|
|
122
|
+
if (blockContent) {
|
|
123
|
+
await writeFile(path.join(context.directories.server, 'lowdefy-build', 'tailwind', '_blocks.html'), '<!-- Block plugin JS content collected at build time -->\n' + blockContent);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
export default writeGlobalsCss;
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
for (const [packageName, operators] of Object.entries(operatorsByPackage)){
|
|
33
33
|
let packageSchemas;
|
|
34
34
|
try {
|
|
35
|
-
packageSchemas = await import(`${packageName}/schemas`);
|
|
35
|
+
packageSchemas = await import(/* webpackIgnore: true */ `${packageName}/schemas`);
|
|
36
36
|
} catch {
|
|
37
37
|
// Package not resolvable from build context (custom plugins) — skip
|
|
38
38
|
}
|
|
@@ -21,7 +21,7 @@ import writeConnectionImports from './writeConnectionImports.js';
|
|
|
21
21
|
import writeIconImports from './writeIconImports.js';
|
|
22
22
|
import writeOperatorImports from './writeOperatorImports.js';
|
|
23
23
|
import writeOperatorSchemaMap from './writeOperatorSchemaMap.js';
|
|
24
|
-
import
|
|
24
|
+
import writeGlobalsCss from './writeGlobalsCss.js';
|
|
25
25
|
async function writePluginImports({ components, context }) {
|
|
26
26
|
await writeActionImports({
|
|
27
27
|
components,
|
|
@@ -59,9 +59,14 @@ async function writePluginImports({ components, context }) {
|
|
|
59
59
|
components,
|
|
60
60
|
context
|
|
61
61
|
});
|
|
62
|
-
await
|
|
62
|
+
await writeGlobalsCss({
|
|
63
63
|
components,
|
|
64
64
|
context
|
|
65
65
|
});
|
|
66
|
+
// Write block package names for Next.js transpilePackages (CSS imports).
|
|
67
|
+
const blockPackages = [
|
|
68
|
+
...new Set((components.imports.blocks ?? []).map((b)=>b.package))
|
|
69
|
+
];
|
|
70
|
+
await context.writeBuildArtifact('blockPackages.json', JSON.stringify(blockPackages));
|
|
66
71
|
}
|
|
67
72
|
export default writePluginImports;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/ import { type, serializer } from '@lowdefy/helpers';
|
|
16
|
+
async function writeTheme({ components, context }) {
|
|
17
|
+
if (type.isNone(components.theme)) {
|
|
18
|
+
components.theme = {};
|
|
19
|
+
}
|
|
20
|
+
if (!type.isObject(components.theme)) {
|
|
21
|
+
throw new Error('Theme is not an object.');
|
|
22
|
+
}
|
|
23
|
+
if (type.isNone(components.theme.darkMode)) {
|
|
24
|
+
components.theme.darkMode = 'system';
|
|
25
|
+
}
|
|
26
|
+
await context.writeBuildArtifact('theme.json', serializer.serializeToString(components.theme));
|
|
27
|
+
}
|
|
28
|
+
export default writeTheme;
|
package/dist/createContext.js
CHANGED
|
@@ -25,6 +25,7 @@ function createContext({ customTypesMap, directories, logger, refResolver, stage
|
|
|
25
25
|
directories,
|
|
26
26
|
errors: [],
|
|
27
27
|
jsMap: {},
|
|
28
|
+
warnings: [],
|
|
28
29
|
keyMap: {},
|
|
29
30
|
logger,
|
|
30
31
|
readConfigFile: createReadConfigFile({
|
|
@@ -60,6 +61,7 @@ function createContext({ customTypesMap, directories, logger, refResolver, stage
|
|
|
60
61
|
directories
|
|
61
62
|
})
|
|
62
63
|
};
|
|
64
|
+
context.blockMetas = context.typesMap.blockMetas ?? {};
|
|
63
65
|
context.handleError = createBuildHandleError({
|
|
64
66
|
context
|
|
65
67
|
});
|