@tamagui/cli 2.7.7 → 3.0.0-beta.637.1
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/add.cjs +77 -87
- package/dist/build.cjs +415 -277
- package/dist/cli.cjs +333 -340
- package/dist/generate-prompt.cjs +344 -357
- package/dist/generate.cjs +46 -54
- package/dist/index.cjs +2 -1
- package/dist/migrate.cjs +370 -0
- package/dist/to-tailwind-default-config.cjs +778 -0
- package/dist/to-tailwind.cjs +214 -0
- package/dist/update-template.cjs +44 -52
- package/dist/update.cjs +15 -18
- package/dist/upgrade.cjs +407 -398
- package/dist/utils.cjs +85 -101
- package/metro.cjs +1 -0
- package/metro.d.ts +1 -0
- package/metro.mjs +1 -0
- package/package.json +41 -12
- package/src/build.ts +574 -363
- package/src/cli.ts +83 -12
- package/src/generate-prompt.ts +16 -24
- package/src/migrate.ts +354 -0
- package/src/to-tailwind-default-config.ts +755 -0
- package/src/to-tailwind.ts +313 -0
- package/src/utils.ts +11 -9
- package/types/add.d.ts +1 -1
- package/types/add.d.ts.map +1 -1
- package/types/build.d.ts +1 -1
- package/types/build.d.ts.map +1 -1
- package/types/migrate.d.ts +7 -0
- package/types/migrate.d.ts.map +1 -0
- package/types/to-tailwind-default-config.d.ts +53 -0
- package/types/to-tailwind-default-config.d.ts.map +1 -0
- package/types/to-tailwind.d.ts +16 -0
- package/types/to-tailwind.d.ts.map +1 -0
- package/types/utils.d.ts.map +1 -1
- package/vite.cjs +1 -0
- package/vite.d.ts +1 -0
- package/vite.mjs +1 -0
package/dist/build.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -5,36 +6,29 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
5
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
6
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
8
|
var __export = (target, all) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
for (var name in all) __defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true
|
|
12
|
+
});
|
|
12
13
|
};
|
|
13
14
|
var __copyProps = (to, from, except, desc) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
17
|
+
get: () => from[key],
|
|
18
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
21
22
|
};
|
|
22
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
26
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
27
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
28
|
-
value: mod,
|
|
29
|
-
enumerable: true
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
30
26
|
}) : target, mod));
|
|
31
|
-
var __toCommonJS = mod => __copyProps(__defProp({}, "__esModule", {
|
|
32
|
-
value: true
|
|
33
|
-
}), mod);
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
34
28
|
var build_exports = {};
|
|
35
29
|
__export(build_exports, {
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
build: () => build,
|
|
31
|
+
insertCssImport: () => insertCssImport
|
|
38
32
|
});
|
|
39
33
|
module.exports = __toCommonJS(build_exports);
|
|
40
34
|
var import_static = require("@tamagui/static");
|
|
@@ -45,270 +39,414 @@ var import_node_path = require("node:path");
|
|
|
45
39
|
var import_node_os = require("node:os");
|
|
46
40
|
var import_node_child_process = require("node:child_process");
|
|
47
41
|
var import_node_crypto = require("node:crypto");
|
|
42
|
+
var import_node_module = require("node:module");
|
|
43
|
+
var import_typescript = require("typescript");
|
|
44
|
+
const import_meta = {};
|
|
45
|
+
const cliVersion = (0, import_node_module.createRequire)(typeof __filename === "string" ? __filename : import_meta.url)("@tamagui/cli/package.json").version;
|
|
48
46
|
function insertCssImport(jsContent, cssImport) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
const directiveMatch = jsContent.match(/^(['"])use (client|server)\1;?\n?/);
|
|
48
|
+
if (directiveMatch) {
|
|
49
|
+
const directive = directiveMatch[0];
|
|
50
|
+
return `${directive}${cssImport}
|
|
53
51
|
${jsContent.slice(directive.length)}`;
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
}
|
|
53
|
+
return `${cssImport}
|
|
56
54
|
${jsContent}`;
|
|
57
55
|
}
|
|
58
|
-
const build = async options => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
56
|
+
const build = async (options) => {
|
|
57
|
+
const sourceDir = options.dir ?? ".";
|
|
58
|
+
const outputDir = options.output;
|
|
59
|
+
const outputAround = options.outputAround || false;
|
|
60
|
+
const promises = [];
|
|
61
|
+
const isDryRun = options.dryRun || false;
|
|
62
|
+
const trackedFiles = [];
|
|
63
|
+
const trackedPaths = /* @__PURE__ */ new Set();
|
|
64
|
+
const restoreDir = options.runCommand ? (0, import_node_path.join)((0, import_node_os.tmpdir)(), `tamagui-restore-${process.pid}`) : null;
|
|
65
|
+
if (restoreDir) await (0, import_fs_extra.mkdir)(restoreDir, { recursive: true });
|
|
66
|
+
let didRestore = false;
|
|
67
|
+
const restoreTrackedFiles = async (force = false) => {
|
|
68
|
+
if (didRestore) return;
|
|
69
|
+
await restoreFiles(trackedFiles, restoreDir, force);
|
|
70
|
+
didRestore = true;
|
|
71
|
+
};
|
|
72
|
+
try {
|
|
73
|
+
const trackFile = async (filePath) => {
|
|
74
|
+
if (!restoreDir || trackedPaths.has(filePath)) return;
|
|
75
|
+
trackedPaths.add(filePath);
|
|
76
|
+
if (!await (0, import_fs_extra.stat)(filePath).catch(() => null)) {
|
|
77
|
+
trackedFiles.push({
|
|
78
|
+
path: filePath,
|
|
79
|
+
hardlinkPath: "",
|
|
80
|
+
mtimeAfterWrite: 0
|
|
81
|
+
});
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const hash = (0, import_node_crypto.createHash)("md5").update(filePath).digest("hex");
|
|
85
|
+
const backupPath = (0, import_node_path.join)(restoreDir, hash);
|
|
86
|
+
await (0, import_fs_extra.copyFile)(filePath, backupPath);
|
|
87
|
+
trackedFiles.push({
|
|
88
|
+
path: filePath,
|
|
89
|
+
hardlinkPath: backupPath,
|
|
90
|
+
mtimeAfterWrite: 0
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
const recordMtime = async (filePath) => {
|
|
94
|
+
if (!restoreDir) return;
|
|
95
|
+
const tracked = trackedFiles.find((item) => item.path === filePath);
|
|
96
|
+
if (tracked) tracked.mtimeAfterWrite = (await (0, import_fs_extra.stat)(filePath)).mtimeMs;
|
|
97
|
+
};
|
|
98
|
+
if (isDryRun) console.info("[dry-run] no files will be written\n");
|
|
99
|
+
if (outputDir) await (0, import_fs_extra.mkdir)(outputDir, { recursive: true });
|
|
100
|
+
const loadedOptions = (0, import_static.loadTamaguiBuildConfigSync)(options.tamaguiOptions);
|
|
101
|
+
if (loadedOptions.disable) console.warn(`[tamagui] Note: "disable" option in tamagui.build.ts is being ignored for CLI build command`);
|
|
102
|
+
const buildOptions = {
|
|
103
|
+
...loadedOptions,
|
|
104
|
+
disable: false,
|
|
105
|
+
disableExtraction: false
|
|
106
|
+
};
|
|
107
|
+
const targets = options.target === "both" || !options.target ? ["web", "native"] : [options.target];
|
|
108
|
+
const root = process.cwd();
|
|
109
|
+
const outputCSSPath = buildOptions.outputCSS ? (0, import_node_path.resolve)(root, buildOptions.outputCSS) : null;
|
|
110
|
+
if (outputCSSPath) await trackFile(outputCSSPath);
|
|
111
|
+
const require2 = (0, import_node_module.createRequire)(typeof __filename === "string" ? __filename : import_meta.url);
|
|
112
|
+
const configPath = (0, import_typescript.findConfigFile)(root, import_typescript.sys.fileExists, "tsconfig.json") || (0, import_typescript.findConfigFile)(root, import_typescript.sys.fileExists, "jsconfig.json");
|
|
113
|
+
const compilerOptions = configPath ? (0, import_typescript.parseJsonConfigFileContent)((() => {
|
|
114
|
+
const loaded = (0, import_typescript.readConfigFile)(configPath, import_typescript.sys.readFile);
|
|
115
|
+
if (loaded.error) throw new Error(String(loaded.error.messageText));
|
|
116
|
+
return loaded.config;
|
|
117
|
+
})(), import_typescript.sys, (0, import_node_path.dirname)(configPath)).options : {};
|
|
118
|
+
const resolveCompilerId = (specifier, importer) => {
|
|
119
|
+
const resolved = (0, import_typescript.nodeModuleNameResolver)(specifier, importer, compilerOptions, import_typescript.sys).resolvedModule?.resolvedFileName;
|
|
120
|
+
if (resolved && !resolved.endsWith(".d.ts")) return resolved;
|
|
121
|
+
try {
|
|
122
|
+
return require2.resolve(specifier, { paths: [(0, import_node_path.dirname)(importer), root] });
|
|
123
|
+
} catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const compilerFrontends = /* @__PURE__ */ new Map();
|
|
128
|
+
const compilerProjects = /* @__PURE__ */ new Map();
|
|
129
|
+
for (const target of targets) {
|
|
130
|
+
const targetOptions = {
|
|
131
|
+
...buildOptions,
|
|
132
|
+
platform: target
|
|
133
|
+
};
|
|
134
|
+
const projectInfo = await (0, import_static.loadTamagui)(targetOptions);
|
|
135
|
+
if (!projectInfo) throw new Error(`Unable to load Tamagui for the ${target} build`);
|
|
136
|
+
const componentModules = [.../* @__PURE__ */ new Set(["@tamagui/core", ...targetOptions.components ?? []])].map((moduleName) => {
|
|
137
|
+
const id = resolveCompilerId(moduleName, (0, import_node_path.join)(root, "__tamagui_cli__.tsx"));
|
|
138
|
+
if (!id) throw new Error(`Unable to resolve compiler component ${moduleName}`);
|
|
139
|
+
return {
|
|
140
|
+
moduleName,
|
|
141
|
+
id
|
|
142
|
+
};
|
|
143
|
+
});
|
|
144
|
+
compilerProjects.set(target, {
|
|
145
|
+
projectInfo,
|
|
146
|
+
componentModules,
|
|
147
|
+
generation: (0, import_node_crypto.createHash)("sha256").update(target).update("\0").update(buildOptions.config ?? "tamagui.config.ts").update("\0").update(JSON.stringify(targetOptions.components ?? [])).update("\0").update(String(!!targetOptions.disablePartialExtraction)).update("\0").update(String(target === "native" && !!targetOptions.experimental?.nativeFastPath)).digest("hex"),
|
|
148
|
+
disablePartialExtraction: targetOptions.disablePartialExtraction,
|
|
149
|
+
experimentalNativeFastPath: target === "native" && targetOptions.experimental?.nativeFastPath === true,
|
|
150
|
+
cacheStamp: (0, import_static.compilerProjectStamp)({
|
|
151
|
+
stampSources: projectInfo.stampSources ?? [],
|
|
152
|
+
hostVersions: [`@tamagui/cli@${cliVersion}`],
|
|
153
|
+
target,
|
|
154
|
+
componentModules,
|
|
155
|
+
disablePartialExtraction: !!targetOptions.disablePartialExtraction,
|
|
156
|
+
experimentalNativeFastPath: target === "native" && targetOptions.experimental?.nativeFastPath === true,
|
|
157
|
+
zeroRuntime: false,
|
|
158
|
+
development: process.env.NODE_ENV === "development"
|
|
159
|
+
})
|
|
160
|
+
});
|
|
161
|
+
compilerFrontends.set(target, new import_static.CompilerFrontend());
|
|
162
|
+
}
|
|
163
|
+
if (outputCSSPath) await recordMtime(outputCSSPath);
|
|
164
|
+
const compileTarget = async (target, sourcePath, source) => {
|
|
165
|
+
const compiler = compilerFrontends.get(target);
|
|
166
|
+
const project = compilerProjects.get(target);
|
|
167
|
+
return compiler.compile({
|
|
168
|
+
id: sourcePath,
|
|
169
|
+
source,
|
|
170
|
+
root,
|
|
171
|
+
target,
|
|
172
|
+
project,
|
|
173
|
+
resolve: async (specifier, importer) => {
|
|
174
|
+
const id = resolveCompilerId(specifier, importer);
|
|
175
|
+
return id ? {
|
|
176
|
+
id,
|
|
177
|
+
external: id.includes("/node_modules/")
|
|
178
|
+
} : null;
|
|
179
|
+
},
|
|
180
|
+
load: async (id) => {
|
|
181
|
+
try {
|
|
182
|
+
return await (0, import_fs_extra.readFile)(id.split(/[?#]/, 1)[0], "utf8");
|
|
183
|
+
} catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
const allFiles = [];
|
|
190
|
+
const watchPattern = sourceDir.match(/\.(tsx|jsx)$/) ? sourceDir : `${sourceDir}/**/*.{tsx,jsx}`;
|
|
191
|
+
const sourceRoot = sourceDir.match(/\.(tsx|jsx)$/) ? (0, import_node_path.dirname)((0, import_node_path.resolve)(sourceDir)) : (0, import_node_path.resolve)(sourceDir);
|
|
192
|
+
await new Promise((res) => {
|
|
193
|
+
const watcher = import_chokidar.default.watch(watchPattern, { ignoreInitial: false });
|
|
194
|
+
watcher.on("add", (relativePath) => {
|
|
195
|
+
const sourcePath = (0, import_node_path.resolve)(process.cwd(), relativePath);
|
|
196
|
+
if (options.exclude && import_micromatch.default.contains(relativePath, options.exclude)) return;
|
|
197
|
+
if (options.include && !import_micromatch.default.contains(relativePath, options.include)) return;
|
|
198
|
+
allFiles.push(sourcePath);
|
|
199
|
+
}).on("ready", () => {
|
|
200
|
+
watcher.close().then(() => res());
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
allFiles.sort();
|
|
204
|
+
const fileToTargets = /* @__PURE__ */ new Map();
|
|
205
|
+
for (const sourcePath of allFiles) {
|
|
206
|
+
const platformMatch = sourcePath.match(/\.(web|native|ios|android)\.(tsx|jsx)$/);
|
|
207
|
+
let filePlatforms = [];
|
|
208
|
+
if (platformMatch) {
|
|
209
|
+
const platform = platformMatch[1];
|
|
210
|
+
if (platform === "web") filePlatforms = ["web"];
|
|
211
|
+
else if (platform === "native" || platform === "ios" || platform === "android") filePlatforms = ["native"];
|
|
212
|
+
} else {
|
|
213
|
+
const basePath = sourcePath.replace(/\.(tsx|jsx)$/, "");
|
|
214
|
+
const hasNative = allFiles.some((f) => f === `${basePath}.native.tsx` || f === `${basePath}.native.jsx` || f === `${basePath}.ios.tsx` || f === `${basePath}.ios.jsx` || f === `${basePath}.android.tsx` || f === `${basePath}.android.jsx`);
|
|
215
|
+
const hasWeb = allFiles.some((f) => f === `${basePath}.web.tsx` || f === `${basePath}.web.jsx`);
|
|
216
|
+
filePlatforms = targets.filter((target) => {
|
|
217
|
+
if (target === "native" && hasNative) return false;
|
|
218
|
+
if (target === "web" && hasWeb) return false;
|
|
219
|
+
return true;
|
|
220
|
+
});
|
|
221
|
+
if (hasWeb && hasNative) filePlatforms = [];
|
|
222
|
+
}
|
|
223
|
+
if (filePlatforms.length > 0) fileToTargets.set(sourcePath, filePlatforms);
|
|
224
|
+
}
|
|
225
|
+
const stats = {
|
|
226
|
+
filesProcessed: 0,
|
|
227
|
+
optimized: 0,
|
|
228
|
+
flattened: 0,
|
|
229
|
+
styled: 0,
|
|
230
|
+
found: 0
|
|
231
|
+
};
|
|
232
|
+
if (options.debug) process.env.NODE_ENV ||= "development";
|
|
233
|
+
const sources = /* @__PURE__ */ new Map();
|
|
234
|
+
await Promise.all([...fileToTargets.keys()].map(async (sourcePath) => {
|
|
235
|
+
sources.set(sourcePath, await (0, import_fs_extra.readFile)(sourcePath, "utf-8"));
|
|
236
|
+
}));
|
|
237
|
+
const buildWebFile = async (sourcePath, originalSource) => {
|
|
238
|
+
if (isDryRun) console.info(`
|
|
239
|
+
${sourcePath} [web]`);
|
|
240
|
+
const out = await compileTarget("web", sourcePath, originalSource);
|
|
241
|
+
if (out.output.changed || out.plan.stats.found > 0) {
|
|
242
|
+
stats.filesProcessed++;
|
|
243
|
+
stats.optimized += out.plan.stats.lowered - out.plan.stats.flattened;
|
|
244
|
+
stats.flattened += out.plan.stats.flattened;
|
|
245
|
+
stats.styled += out.plan.stats.styled;
|
|
246
|
+
stats.found += out.plan.stats.found;
|
|
247
|
+
if (isDryRun) {
|
|
248
|
+
if (out.plan.css) console.info(`
|
|
173
249
|
css:
|
|
174
|
-
${out.
|
|
175
|
-
|
|
250
|
+
${out.plan.css}`);
|
|
251
|
+
console.info(`
|
|
176
252
|
js:
|
|
177
|
-
${
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
...buildOptions,
|
|
205
|
-
platform: "native"
|
|
206
|
-
};
|
|
207
|
-
const nativeOut = (0, import_static.extractToNative)(sourcePath, originalSource, nativeTamaguiOptions);
|
|
208
|
-
if (isDryRun) {
|
|
209
|
-
if (nativeOut.code) console.info(`
|
|
253
|
+
${out.output.code}`);
|
|
254
|
+
} else {
|
|
255
|
+
const relPath = outputDir ? (0, import_node_path.relative)(sourceRoot, sourcePath) : (0, import_node_path.basename)(sourcePath);
|
|
256
|
+
const cssName = "_" + (0, import_node_path.basename)(sourcePath, (0, import_node_path.extname)(sourcePath));
|
|
257
|
+
const outputBase = outputDir ? (0, import_node_path.join)(outputDir, (0, import_node_path.dirname)(relPath)) : (0, import_node_path.dirname)(sourcePath);
|
|
258
|
+
if (outputDir) await (0, import_fs_extra.mkdir)(outputBase, { recursive: true });
|
|
259
|
+
const stylePath = (0, import_node_path.join)(outputBase, cssName + ".css");
|
|
260
|
+
const cssImport = `import "./${cssName}.css"`;
|
|
261
|
+
const code = out.plan.css ? insertCssImport(out.output.code, cssImport) : out.output.code;
|
|
262
|
+
const webOutputPath = outputDir ? (0, import_node_path.join)(outputDir, relPath) : sourcePath;
|
|
263
|
+
if (!outputDir) await trackFile(sourcePath);
|
|
264
|
+
await (0, import_fs_extra.writeFile)(webOutputPath, code, "utf-8");
|
|
265
|
+
if (!outputDir) await recordMtime(sourcePath);
|
|
266
|
+
if (out.plan.css) await (0, import_fs_extra.writeFile)(stylePath, out.plan.css, "utf-8");
|
|
267
|
+
if (!outputDir && out.plan.css) trackedFiles.push({
|
|
268
|
+
path: stylePath,
|
|
269
|
+
hardlinkPath: "",
|
|
270
|
+
mtimeAfterWrite: (await (0, import_fs_extra.stat)(stylePath)).mtimeMs
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
} else if (isDryRun) console.info(` web: no output`);
|
|
274
|
+
};
|
|
275
|
+
const buildNativeFile = async (sourcePath, filePlatforms, originalSource) => {
|
|
276
|
+
if (isDryRun) console.info(`
|
|
277
|
+
${sourcePath} [native]`);
|
|
278
|
+
const nativeOut = await compileTarget("native", sourcePath, originalSource);
|
|
279
|
+
if (isDryRun) if (nativeOut.output.code) console.info(`
|
|
210
280
|
native:
|
|
211
|
-
${nativeOut.code}`);
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
281
|
+
${nativeOut.output.code}`);
|
|
282
|
+
else console.info(` native: no output`);
|
|
283
|
+
else {
|
|
284
|
+
let nativeOutputPath = sourcePath;
|
|
285
|
+
const needsNativeSuffix = !/\.(web|native|ios|android)\.(tsx|jsx)$/.test(sourcePath) && (filePlatforms.length > 1 || outputAround);
|
|
286
|
+
if (outputAround) {
|
|
287
|
+
nativeOutputPath = sourcePath.replace(/\.(tsx|jsx)$/, ".native.$1");
|
|
288
|
+
if (await (0, import_fs_extra.stat)(nativeOutputPath).catch(() => null)) throw new Error(`--output-around: ${nativeOutputPath} already exists. Remove it first or use --output instead.`);
|
|
289
|
+
} else if (outputDir) {
|
|
290
|
+
const relPath = (0, import_node_path.relative)(sourceRoot, sourcePath);
|
|
291
|
+
const outputRelPath = needsNativeSuffix ? relPath.replace(/\.(tsx|jsx)$/, ".native.$1") : relPath;
|
|
292
|
+
nativeOutputPath = (0, import_node_path.join)(outputDir, outputRelPath);
|
|
293
|
+
await (0, import_fs_extra.mkdir)((0, import_node_path.dirname)(nativeOutputPath), { recursive: true });
|
|
294
|
+
} else if (needsNativeSuffix) nativeOutputPath = sourcePath.replace(/\.(tsx|jsx)$/, ".native.$1");
|
|
295
|
+
if (nativeOut.output.code) {
|
|
296
|
+
if (nativeOut.output.changed) {
|
|
297
|
+
stats.filesProcessed++;
|
|
298
|
+
stats.flattened += nativeOut.plan.stats.flattened;
|
|
299
|
+
}
|
|
300
|
+
if (!outputDir && !outputAround && (nativeOutputPath === sourcePath || filePlatforms.length === 1)) await trackFile(nativeOutputPath);
|
|
301
|
+
await (0, import_fs_extra.writeFile)(nativeOutputPath, nativeOut.output.code, "utf-8");
|
|
302
|
+
if (!outputDir && !outputAround) await recordMtime(nativeOutputPath);
|
|
303
|
+
if (!outputDir && !outputAround && nativeOutputPath !== sourcePath && filePlatforms.length > 1) trackedFiles.push({
|
|
304
|
+
path: nativeOutputPath,
|
|
305
|
+
hardlinkPath: "",
|
|
306
|
+
mtimeAfterWrite: (await (0, import_fs_extra.stat)(nativeOutputPath)).mtimeMs
|
|
307
|
+
});
|
|
308
|
+
if (outputAround) console.info(` \u2192 ${nativeOutputPath}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
for (const target of targets) {
|
|
313
|
+
process.env.TAMAGUI_TARGET = target;
|
|
314
|
+
const targetPromises = [...fileToTargets].filter(([, filePlatforms]) => filePlatforms.includes(target)).map(([sourcePath, filePlatforms]) => target === "web" ? buildWebFile(sourcePath, sources.get(sourcePath)) : buildNativeFile(sourcePath, filePlatforms, sources.get(sourcePath)));
|
|
315
|
+
promises.push(...targetPromises);
|
|
316
|
+
await Promise.all(targetPromises);
|
|
317
|
+
}
|
|
318
|
+
if (isDryRun) console.info(`
|
|
247
319
|
${stats.filesProcessed} files | ${stats.found} found | ${stats.optimized} optimized | ${stats.flattened} flattened | ${stats.styled} styled
|
|
248
320
|
`);
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
321
|
+
if (options.expectOptimizations !== void 0) {
|
|
322
|
+
const totalOptimizations = stats.optimized + stats.flattened;
|
|
323
|
+
if (totalOptimizations < options.expectOptimizations) {
|
|
324
|
+
console.error(`
|
|
253
325
|
Expected at least ${options.expectOptimizations} optimizations but only got ${totalOptimizations}`);
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
326
|
+
console.error(`Stats: ${JSON.stringify(stats, null, 2)}`);
|
|
327
|
+
await restoreTrackedFiles(true);
|
|
328
|
+
throw new Error(`Expected at least ${options.expectOptimizations} optimizations but only got ${totalOptimizations}`);
|
|
329
|
+
}
|
|
330
|
+
console.info(`
|
|
258
331
|
\u2713 Met optimization target: ${totalOptimizations} >= ${options.expectOptimizations}`);
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
stdio: "inherit"
|
|
268
|
-
});
|
|
269
|
-
} catch (err) {
|
|
270
|
-
console.error(`
|
|
332
|
+
}
|
|
333
|
+
if (options.runCommand && options.runCommand.length > 0) {
|
|
334
|
+
let commandFailed = true;
|
|
335
|
+
try {
|
|
336
|
+
await runCommand(options.runCommand, () => restoreTrackedFiles(true));
|
|
337
|
+
commandFailed = false;
|
|
338
|
+
} catch (err) {
|
|
339
|
+
console.error(`
|
|
271
340
|
Command failed with exit code ${err.status || 1}`);
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
341
|
+
throw err;
|
|
342
|
+
} finally {
|
|
343
|
+
await restoreTrackedFiles(commandFailed);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
stats,
|
|
348
|
+
trackedFiles
|
|
349
|
+
};
|
|
350
|
+
} catch (error) {
|
|
351
|
+
await Promise.allSettled(promises);
|
|
352
|
+
await restoreTrackedFiles(true);
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
281
355
|
};
|
|
282
|
-
async function
|
|
283
|
-
|
|
284
|
-
|
|
356
|
+
async function runCommand(command, restore) {
|
|
357
|
+
await new Promise((resolveCommand, rejectCommand) => {
|
|
358
|
+
const child = (0, import_node_child_process.spawn)(command[0], command.slice(1), { stdio: "inherit" });
|
|
359
|
+
let settled = false;
|
|
360
|
+
let listenersRestored = false;
|
|
361
|
+
const interruptListeners = process.listeners("SIGINT");
|
|
362
|
+
const terminateListeners = process.listeners("SIGTERM");
|
|
363
|
+
process.removeAllListeners("SIGINT");
|
|
364
|
+
process.removeAllListeners("SIGTERM");
|
|
365
|
+
const cleanup = () => {
|
|
366
|
+
process.off("SIGINT", onInterrupt);
|
|
367
|
+
process.off("SIGTERM", onTerminate);
|
|
368
|
+
if (listenersRestored) return;
|
|
369
|
+
listenersRestored = true;
|
|
370
|
+
for (const listener of interruptListeners) process.on("SIGINT", listener);
|
|
371
|
+
for (const listener of terminateListeners) process.on("SIGTERM", listener);
|
|
372
|
+
};
|
|
373
|
+
const finishSignal = (signal) => {
|
|
374
|
+
if (settled) return;
|
|
375
|
+
settled = true;
|
|
376
|
+
(async () => {
|
|
377
|
+
const childExited = child.exitCode === null && child.signalCode === null ? new Promise((resolveExit) => child.once("exit", () => resolveExit())) : Promise.resolve();
|
|
378
|
+
child.kill(signal);
|
|
379
|
+
await childExited;
|
|
380
|
+
try {
|
|
381
|
+
await restore();
|
|
382
|
+
} finally {
|
|
383
|
+
cleanup();
|
|
384
|
+
process.exit(signal === "SIGINT" ? 130 : 143);
|
|
385
|
+
}
|
|
386
|
+
})();
|
|
387
|
+
};
|
|
388
|
+
const onInterrupt = () => finishSignal("SIGINT");
|
|
389
|
+
const onTerminate = () => finishSignal("SIGTERM");
|
|
390
|
+
process.once("SIGINT", onInterrupt);
|
|
391
|
+
process.once("SIGTERM", onTerminate);
|
|
392
|
+
console.info(`
|
|
393
|
+
Running: ${command.join(" ")}
|
|
394
|
+
`);
|
|
395
|
+
child.once("error", (error) => {
|
|
396
|
+
if (settled) return;
|
|
397
|
+
settled = true;
|
|
398
|
+
cleanup();
|
|
399
|
+
rejectCommand(error);
|
|
400
|
+
});
|
|
401
|
+
child.once("exit", (code, signal) => {
|
|
402
|
+
if (settled) return;
|
|
403
|
+
settled = true;
|
|
404
|
+
cleanup();
|
|
405
|
+
if (code === 0) {
|
|
406
|
+
resolveCommand();
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
const error = /* @__PURE__ */ new Error(signal ? `Command terminated by ${signal}` : `Command exited with code ${code}`);
|
|
410
|
+
error.status = code ?? 1;
|
|
411
|
+
rejectCommand(error);
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
async function restoreFiles(trackedFiles, restoreDir, force = false) {
|
|
416
|
+
if (!restoreDir) return;
|
|
417
|
+
if (trackedFiles.length === 0) {
|
|
418
|
+
await (0, import_fs_extra.rm)(restoreDir, {
|
|
419
|
+
recursive: true,
|
|
420
|
+
force: true
|
|
421
|
+
});
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
console.info(`
|
|
285
425
|
Restoring ${trackedFiles.length} files...`);
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
console.info(` Restored: ${restored}, Deleted: ${deleted}, Skipped: ${skipped}`);
|
|
314
|
-
}
|
|
426
|
+
let restored = 0;
|
|
427
|
+
let skipped = 0;
|
|
428
|
+
let deleted = 0;
|
|
429
|
+
for (const tracked of trackedFiles) try {
|
|
430
|
+
const currentStat = await (0, import_fs_extra.stat)(tracked.path).catch(() => null);
|
|
431
|
+
if (!force && currentStat && currentStat.mtimeMs !== tracked.mtimeAfterWrite) {
|
|
432
|
+
console.warn(` Skipping ${tracked.path} - modified during build`);
|
|
433
|
+
skipped++;
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
if (tracked.hardlinkPath === "") {
|
|
437
|
+
await (0, import_fs_extra.rm)(tracked.path, { force: true });
|
|
438
|
+
deleted++;
|
|
439
|
+
} else {
|
|
440
|
+
await (0, import_fs_extra.copyFile)(tracked.hardlinkPath, tracked.path);
|
|
441
|
+
restored++;
|
|
442
|
+
}
|
|
443
|
+
} catch (err) {
|
|
444
|
+
console.warn(` Failed to restore ${tracked.path}: ${err.message}`);
|
|
445
|
+
skipped++;
|
|
446
|
+
}
|
|
447
|
+
await (0, import_fs_extra.rm)(restoreDir, {
|
|
448
|
+
recursive: true,
|
|
449
|
+
force: true
|
|
450
|
+
});
|
|
451
|
+
console.info(` Restored: ${restored}, Deleted: ${deleted}, Skipped: ${skipped}`);
|
|
452
|
+
}
|