Skip to content

Commit 1435eef

Browse files
feat: build transient native dependencies (#5643)
Co-authored-by: Igor Randjelovic <[email protected]>
1 parent 356630a commit 1435eef

File tree

12 files changed

+325
-133
lines changed

12 files changed

+325
-133
lines changed

‎lib/definitions/android-plugin-migrator.d.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ interface IBuildAndroidPluginData extends Partial<IProjectDir>{
4444
* Optional custom Gradle path.
4545
*/
4646
gradlePath?: string;
47-
48-
/**
47+
48+
/**
4949
* Optional custom Gradle arguments.
5050
*/
51-
gradleArgs?: string,
51+
gradleArgs?: string;
5252
}

‎lib/services/android-plugin-build-service.ts‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,8 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService{
258258
awaitthis.setupGradle(
259259
pluginTempDir,
260260
options.platformsAndroidDirPath,
261-
options.projectDir
261+
options.projectDir,
262+
options.pluginName
262263
);
263264
awaitthis.buildPlugin({
264265
gradlePath: options.gradlePath,
@@ -398,7 +399,8 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService{
398399
privateasyncsetupGradle(
399400
pluginTempDir: string,
400401
platformsAndroidDirPath: string,
401-
projectDir: string
402+
projectDir: string,
403+
pluginName: string
402404
): Promise<void>{
403405
constgradleTemplatePath=path.resolve(
404406
path.join(__dirname,"../../vendor/gradle-plugin")
@@ -419,6 +421,7 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService{
419421
buildGradlePath,
420422
runtimeGradleVersions.gradleAndroidPluginVersion
421423
);
424+
this.replaceFileContent(buildGradlePath,"{{pluginName}}",pluginName);
422425
}
423426

424427
privateasyncgetRuntimeGradleVersions(
@@ -729,7 +732,7 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService{
729732
`-PcompileSdk=android-${pluginBuildSettings.androidToolsInfo.compileSdkVersion}`,
730733
`-PbuildToolsVersion=${pluginBuildSettings.androidToolsInfo.buildToolsVersion}`,
731734
`-PappPath=${this.$projectData.getAppDirectoryPath()}`,
732-
`-PappResourcesPath=${this.$projectData.getAppResourcesDirectoryPath()}`
735+
`-PappResourcesPath=${this.$projectData.getAppResourcesDirectoryPath()}`,
733736
];
734737
if(pluginBuildSettings.gradleArgs){
735738
localArgs.push(pluginBuildSettings.gradleArgs);

‎lib/services/android-project-service.ts‎

Lines changed: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,71 @@ import{IInjector } from "../common/definitions/yok"
4848
import{injector}from"../common/yok";
4949
import{INotConfiguredEnvOptions}from"../common/definitions/commands";
5050

51+
interfaceNativeDependency{
52+
name: string;
53+
directory: string;
54+
dependencies: string[];
55+
}
56+
57+
//
58+
// we sort the native dependencies topologically to make sure they are processed in the right order
59+
// native dependenciess need to be sorted so the deepst dependencies are built before it's parents
60+
//
61+
// for example, given this dep structure (assuming these are all native dependencies that need to be built)
62+
// |- dep1
63+
// |- dep2
64+
// |- dep3
65+
// |- dep4
66+
// |-dep5
67+
// |- dep6
68+
//
69+
// It is sorted:
70+
// |- dep1 - doesn't depend on anything, so the order stays the same as in the input list
71+
// |- dep3 - doesn't depend on anything, so the order stays the same as in the input list
72+
// |- dep5 - doesn't depend on anything, so the order stays the same as in the input list
73+
// |- dep6 - doesn't depend on anything, so the order stays the same as in the input list
74+
// |- dep4 - depends on dep6, so dep6 must be built first, ie above ^
75+
// |- dep2 - depends on dep3, dep4, dep5 and dep6, so all of them must be built first
76+
//
77+
// for more details see: https://wikiless.org/wiki/Topological_sorting?lang=en
78+
//
79+
functiontopologicalSortNativeDependencies(
80+
nativeDeps: NativeDependency[],
81+
start: NativeDependency[]=[],
82+
depth=0
83+
): NativeDependency[]{
84+
constprocessedDeps=nativeDeps.reduce(
85+
(accumulator,nativeDep: NativeDependency)=>{
86+
if(
87+
nativeDep.dependencies.every(
88+
Array.prototype.includes,
89+
accumulator.map((n)=>n.name)
90+
)
91+
){
92+
accumulator.push(nativeDep);
93+
}
94+
returnaccumulator;
95+
},
96+
start
97+
);
98+
99+
constremainingDeps=nativeDeps.filter(
100+
(nativeDep)=>!processedDeps.includes(nativeDep)
101+
);
102+
103+
// recurse if we still have unprocessed deps
104+
// the second condition here prevents infinite recursion
105+
if(remainingDeps.length&&depth<=nativeDeps.length){
106+
returntopologicalSortNativeDependencies(
107+
remainingDeps,
108+
processedDeps,
109+
depth+1
110+
);
111+
}
112+
113+
returnprocessedDeps;
114+
}
115+
51116
exportclassAndroidProjectServiceextendsprojectServiceBaseLib.PlatformProjectServiceBase{
52117
privatestaticVALUES_DIRNAME="values";
53118
privatestaticVALUES_VERSION_DIRNAME_PREFIX=
@@ -635,10 +700,10 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
635700
publicasyncbeforePrepareAllPlugins(
636701
projectData: IProjectData,
637702
dependencies?: IDependencyData[]
638-
): Promise<void>{
703+
): Promise<IDependencyData[]>{
639704
if(dependencies){
640705
dependencies=this.filterUniqueDependencies(dependencies);
641-
this.provideDependenciesJson(projectData,dependencies);
706+
returnthis.provideDependenciesJson(projectData,dependencies);
642707
}
643708
}
644709

@@ -666,7 +731,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
666731
privateprovideDependenciesJson(
667732
projectData: IProjectData,
668733
dependencies: IDependencyData[]
669-
): void{
734+
): IDependencyData[]{
670735
constplatformDir=path.join(
671736
projectData.platformsDir,
672737
AndroidProjectService.ANDROID_PLATFORM_NAME
@@ -675,15 +740,37 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
675740
platformDir,
676741
constants.DEPENDENCIES_JSON_NAME
677742
);
678-
constnativeDependencies=dependencies
679-
.filter(AndroidProjectService.isNativeAndroidDependency)
680-
.map(({ name, directory })=>({
681-
name,
682-
directory: path.relative(platformDir,directory),
683-
}));
684-
constjsonContent=JSON.stringify(nativeDependencies,null,4);
743+
letnativeDependencyData=dependencies.filter(
744+
AndroidProjectService.isNativeAndroidDependency
745+
);
685746

747+
letnativeDependencies=nativeDependencyData.map(
748+
({ name, directory, dependencies })=>{
749+
return{
750+
name,
751+
directory: path.relative(platformDir,directory),
752+
dependencies: dependencies.filter((dep)=>{
753+
// filter out transient dependencies that don't have native dependencies
754+
return(
755+
nativeDependencyData.findIndex(
756+
(nativeDep)=>nativeDep.name===dep
757+
)!==-1
758+
);
759+
}),
760+
}asNativeDependency;
761+
}
762+
);
763+
nativeDependencies=topologicalSortNativeDependencies(nativeDependencies);
764+
constjsonContent=JSON.stringify(nativeDependencies,null,4);
686765
this.$fs.writeFile(dependenciesJsonPath,jsonContent);
766+
767+
// we sort all the dependencies to respect the topological sorting of the native dependencies
768+
returndependencies.sort(function(a,b){
769+
return(
770+
nativeDependencies.findIndex((n)=>n.name===a.name)-
771+
nativeDependencies.findIndex((n)=>n.name===b.name)
772+
);
773+
});
687774
}
688775

689776
privatestaticisNativeAndroidDependency({

‎lib/services/ios-project-service.ts‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import{IOSProvisionService } from "./ios-provision-service"
1313
import{IOSEntitlementsService}from"./ios-entitlements-service";
1414
import{IOSBuildData}from"../data/build-data";
1515
import{IOSPrepareData}from"../data/prepare-data";
16-
import{BUILD_XCCONFIG_FILE_NAME,CONFIG_FILE_NAME_DISPLAY,IosProjectConstants}from"../constants";
16+
import{
17+
BUILD_XCCONFIG_FILE_NAME,
18+
CONFIG_FILE_NAME_DISPLAY,
19+
IosProjectConstants,
20+
}from"../constants";
1721
import{hook}from"../common/helpers";
1822
import{
1923
IPlatformData,
@@ -29,8 +33,14 @@ import{
2933
IIOSNativeTargetService,
3034
IValidatePlatformOutput,
3135
}from"../definitions/project";
36+
3237
import{IBuildData}from"../definitions/build";
33-
import{IXcprojService,IXcconfigService,IOptions}from"../declarations";
38+
import{
39+
IXcprojService,
40+
IXcconfigService,
41+
IDependencyData,
42+
IOptions,
43+
}from"../declarations";
3444
import{IPluginData,IPluginsService}from"../definitions/plugins";
3545
import{
3646
IFileSystem,
@@ -976,8 +986,11 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
976986
awaitthis.addExtensions(projectData,pluginsData);
977987
}
978988

979-
publicbeforePrepareAllPlugins(): Promise<void>{
980-
returnPromise.resolve();
989+
publicbeforePrepareAllPlugins(
990+
projectData: IProjectData,
991+
dependencies?: IDependencyData[]
992+
): Promise<IDependencyData[]>{
993+
returnPromise.resolve(dependencies);
981994
}
982995

983996
publicasynccheckForChanges(

‎lib/services/platform-environment-requirements.ts‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ export class PlatformEnvironmentRequirements
2424
// private $staticConfig: IStaticConfig,
2525
private$analyticsService: IAnalyticsService,
2626
// @ts-ignore - required by the hook helper!
27-
private$injector: IInjector
28-
)// private $previewQrCodeService: IPreviewQrCodeService
29-
{}
27+
private$injector: IInjector// private $previewQrCodeService: IPreviewQrCodeService
28+
){}
3029

3130
// public get $previewAppController(): IPreviewAppController{
3231
// return this.$injector.resolve("previewAppController");

‎lib/services/project-changes-service.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ export class ProjectChangesService implements IProjectChangesService{
9393
);
9494

9595
this.$nodeModulesDependenciesBuilder
96-
.getProductionDependencies(projectData.projectDir,projectData.ignoredDependencies)
96+
.getProductionDependencies(
97+
projectData.projectDir,
98+
projectData.ignoredDependencies
99+
)
97100
.filter(
98101
(dep)=>
99102
dep.nativescript&&

‎lib/services/webpack/webpack.d.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ declare global{
163163
beforePrepareAllPlugins(
164164
projectData: IProjectData,
165165
dependencies?: IDependencyData[]
166-
): Promise<void>;
166+
): Promise<IDependencyData[]>;
167167

168168
handleNativeDependenciesChange(
169169
projectData: IProjectData,

‎lib/tools/node-modules/node-modules-builder.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ export class NodeModulesBuilder implements INodeModulesBuilder{
1818
platformData,
1919
projectData,
2020
}: IPrepareNodeModulesData): Promise<void>{
21-
constdependencies=this.$nodeModulesDependenciesBuilder.getProductionDependencies(
21+
letdependencies=this.$nodeModulesDependenciesBuilder.getProductionDependencies(
2222
projectData.projectDir,projectData.ignoredDependencies
2323
);
24-
awaitplatformData.platformProjectService.beforePrepareAllPlugins(
24+
dependencies=awaitplatformData.platformProjectService.beforePrepareAllPlugins(
2525
projectData,
2626
dependencies
2727
);

‎lib/tools/node-modules/node-modules-dependencies-builder.ts‎

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import{IDependencyData } from "../../declarations"
55
import{IFileSystem}from"../../common/declarations";
66
import*as_from"lodash";
77
import{injector}from"../../common/yok";
8+
import{resolvePackagePath}from"@rigor789/resolve-package-path";
89

910
interfaceIDependencyDescription{
1011
parent: IDependencyDescription;
@@ -43,7 +44,8 @@ export class NodeModulesDependenciesBuilder
4344
constcurrentModule=queue.shift();
4445
constresolvedDependency=this.findModule(
4546
currentModule,
46-
resolvedDependencies
47+
resolvedDependencies,
48+
projectPath
4749
);
4850

4951
if(
@@ -86,16 +88,29 @@ export class NodeModulesDependenciesBuilder
8688

8789
privatefindModule(
8890
depDescription: IDependencyDescription,
89-
resolvedDependencies: IDependencyData[]
91+
resolvedDependencies: IDependencyData[],
92+
rootPath: string
9093
): IDependencyData{
9194
try{
9295
constparentModulesPath=
9396
depDescription?.parentDir??depDescription?.parent?.parentDir;
94-
constmodulePath=require
95-
.resolve(`${depDescription.name}/package.json`,{
96-
paths: [parentModulesPath],
97-
})
98-
.replace(/[\\/]+package\.json$/,"");
97+
98+
letmodulePath: string=resolvePackagePath(depDescription.name,{
99+
paths: [parentModulesPath],
100+
});
101+
102+
// perhaps traverse up the tree here?
103+
if(!modulePath){
104+
// fallback to searching in the root path
105+
modulePath=resolvePackagePath(depDescription.name,{
106+
paths: [rootPath],
107+
});
108+
}
109+
110+
// if we failed to find the module...
111+
if(!modulePath){
112+
returnnull;
113+
}
99114

100115
// if we already resolved this dependency, we return null to avoid a duplicate resolution
101116
if(

0 commit comments

Comments
(0)