Skip to content

Commit 1ee87fc

Browse files
committed
fix(windows): plugins & .net support
1 parent 5bbe284 commit 1ee87fc

1 file changed

Lines changed: 118 additions & 18 deletions

File tree

lib/services/windows-project-service.ts

Lines changed: 118 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,72 @@ export class WindowsProjectService
304304
platformData.projectRoot,
305305
projectData.projectName,
306306
);
307+
308+
// Attempt to run dotnet-tool to publish/copy DotNetBridge and app projects if available
309+
try {
310+
const marker = path.join(appProjectDir, "dotnet-bridge", "publish", ".dotnet_tool_done");
311+
if (fs.existsSync(marker)) {
312+
this.$logger.info("DotNetBridge publish marker found; skipping dotnet-tool");
313+
}
314+
else {
315+
const arch = process.arch === "arm64" ? "arm64" : "x64";
316+
const exeCandidates = [
317+
process.env.DOTNET_TOOL_PATH,
318+
path.join(platformData.projectRoot, "tools", `dotnet-tool-${arch}.exe`),
319+
path.join(platformData.projectRoot, "tools", "dotnet-tool.exe"),
320+
].filter(Boolean as any);
321+
let exePath: string | null = null;
322+
for (const p of exeCandidates) {
323+
if (p && fs.existsSync(p)) { exePath = p as string; break; }
324+
}
325+
if (exePath) {
326+
this.$logger.info(`Running dotnet-tool: ${exePath}`);
327+
try {
328+
329+
const result = await this.$childProcess.spawnFromEvent(exePath, ["--app-root", platformData.projectRoot, "--dir", "app", "--force"], "close", { cwd: platformData.projectRoot }, { throwError: false });
330+
if (result && result.stdout) { this.$logger.info(result.stdout); }
331+
}
332+
catch (err) {
333+
this.$logger.warn(`dotnet-tool execution failed: ${err}`);
334+
}
335+
336+
// Ensure sentinel exists: if publish/ contains DotNetBridge.dll, write marker so MSBuild waits succeed
337+
try {
338+
const markerPath = path.join(appProjectDir, "dotnet-bridge", "publish", ".dotnet_tool_done");
339+
if (!fs.existsSync(markerPath)) {
340+
const publishDir = path.join(appProjectDir, "dotnet-bridge", "publish");
341+
if (fs.existsSync(publishDir)) {
342+
const files = fs.readdirSync(publishDir);
343+
if (files && files.length > 0) {
344+
const bridgeDll = path.join(publishDir, "DotNetBridge.dll");
345+
if (fs.existsSync(bridgeDll)) {
346+
try {
347+
fs.writeFileSync(markerPath, "done", "utf8");
348+
this.$logger.info(`Created dotnet-tool marker at ${markerPath}`);
349+
}
350+
catch (werr) {
351+
this.$logger.warn(`Failed creating dotnet-tool marker: ${werr}`);
352+
}
353+
}
354+
else {
355+
this.$logger.info(`[NativeScript] publish directory exists but DotNetBridge.dll missing; files=${files.join(',')}`);
356+
}
357+
}
358+
}
359+
else {
360+
this.$logger.info(`[NativeScript] publish directory not found at ${publishDir}`);
361+
}
362+
}
363+
}
364+
catch (e) {
365+
this.$logger.warn(`dotnet-tool sentinel check failed: ${e}`);
366+
}
367+
}
368+
}
369+
}
370+
catch (err) {
371+
this.$logger.warn(`dotnet-tool check failed: ${err}`);
372+
}
307373
const pluginsDir = path.join(appProjectDir, "plugins");
308374

309375
// Ensure plugins directory exists inside the platform app folder (where csproj expects it)
@@ -360,13 +426,14 @@ export class WindowsProjectService
360426
"<Project>",
361427
];
362428
for (const p of stagedPlugins) {
363-
const importPathProps = `plugins\\${p.name}\\plugin.props`;
364-
const importPathTargets = `plugins\\${p.name}\\plugin.targets`;
429+
const pluginRelDir = p.name.split("/").join("\\");
430+
const importPathProps = `$(MSBuildThisFileDirectory)${pluginRelDir}\\plugin.props`;
431+
const importPathTargets = `$(MSBuildThisFileDirectory)${pluginRelDir}\\plugin.targets`;
365432
propsLines.push(
366-
` <Import Project=\"${importPathProps}\" Condition=\"Exists('${importPathProps.replace(/'/g, "''")}')\" />`,
433+
` <Import Project="${importPathProps}" Condition="Exists('${importPathProps}')" />`,
367434
);
368435
targetsLines.push(
369-
` <Import Project=\"${importPathTargets}\" Condition=\"Exists('${importPathTargets.replace(/'/g, "''")}')\" />`,
436+
` <Import Project="${importPathTargets}" Condition="Exists('${importPathTargets}')" />`,
370437
);
371438
}
372439
propsLines.push("</Project>");
@@ -542,22 +609,23 @@ export class WindowsProjectService
542609
);
543610
}
544611

612+
const collectStagedFiles = (root: string): string[] => {
613+
const out: string[] = [];
614+
if (!this.$fs.exists(root)) return out;
615+
const walk = (dir: string) => {
616+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
617+
const full = path.join(dir, e.name);
618+
if (e.isDirectory()) walk(full);
619+
else out.push(path.relative(root, full).split(path.sep).join("\\"));
620+
}
621+
};
622+
walk(root);
623+
return out;
624+
};
625+
545626
// generate plugin.props if not provided
546627
if (!this.$fs.exists(path.join(pluginStageDir, "plugin.props"))) {
547-
const collect = (root: string) => {
548-
const out: string[] = [];
549-
if (!this.$fs.exists(root)) return out;
550-
const walk = (dir: string) => {
551-
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
552-
const full = path.join(dir, e.name);
553-
if (e.isDirectory()) walk(full);
554-
else out.push(path.relative(root, full).split(path.sep).join("\\"));
555-
}
556-
};
557-
walk(root);
558-
return out;
559-
};
560-
const stagedFiles = collect(pluginStageDir);
628+
const stagedFiles = collectStagedFiles(pluginStageDir);
561629
const lines: string[] = [
562630
'<?xml version="1.0" encoding="utf-8"?>',
563631
"<Project>",
@@ -580,6 +648,38 @@ export class WindowsProjectService
580648
lines.join("\n"),
581649
);
582650
}
651+
652+
// generate plugin.targets if not provided — uses an explicit Copy task so
653+
// that DLLs reach bin/ even when EnableMsixTooling=true intercepts Content items.
654+
if (!this.$fs.exists(path.join(pluginStageDir, "plugin.targets"))) {
655+
const stagedFiles = collectStagedFiles(pluginStageDir);
656+
if (stagedFiles.length > 0) {
657+
const safeName = pluginData.name.replace(/[^a-zA-Z0-9]/g, "_");
658+
const pluginOutDir = `plugins\\${pluginData.name.split("/").join("\\")}`;
659+
const lines: string[] = [
660+
'<?xml version="1.0" encoding="utf-8"?>',
661+
"<Project>",
662+
` <Target Name="CopyPlugin_${safeName}" AfterTargets="Build">`,
663+
` <MakeDir Directories="$(OutDir)${pluginOutDir}" />`,
664+
];
665+
for (const f of stagedFiles) {
666+
const rel = f.split(path.sep).join("\\");
667+
lines.push(
668+
` <Copy SourceFiles="$(MSBuildThisFileDirectory)${rel}"`,
669+
);
670+
lines.push(
671+
` DestinationFiles="$(OutDir)${pluginOutDir}\\${rel}"`,
672+
);
673+
lines.push(` SkipUnchangedFiles="true" />`);
674+
}
675+
lines.push(" </Target>");
676+
lines.push("</Project>");
677+
this.$fs.writeFile(
678+
path.join(pluginStageDir, "plugin.targets"),
679+
lines.join("\n"),
680+
);
681+
}
682+
}
583683
}
584684

585685
public async removePluginNativeCode(

0 commit comments

Comments
 (0)