Skip to content

Commit c942129

Browse files
committed
added new option to install packages
1 parent d6d4b8f commit c942129

File tree

8 files changed

+108
-33
lines changed

8 files changed

+108
-33
lines changed

packages/open-next/src/build/compileTagCacheProvider.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import path from "node:path";
22

33
import { openNextResolvePlugin } from "../plugins/resolve.js";
44
import * as buildHelper from "./helper.js";
5+
import { installDependencies } from "./installDeps.js";
56

67
export async function compileTagCacheProvider(
78
options: buildHelper.BuildOptions,
@@ -30,4 +31,9 @@ export async function compileTagCacheProvider(
3031
},
3132
options,
3233
);
34+
35+
installDependencies(
36+
providerPath,
37+
options.config.initializationFunction?.install,
38+
);
3339
}

packages/open-next/src/build/createImageOptimizationBundle.ts

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import cp from "node:child_process";
21
import fs from "node:fs";
32
import { createRequire } from "node:module";
43
import path from "node:path";
@@ -7,6 +6,7 @@ import logger from "../logger.js";
76
import { openNextReplacementPlugin } from "../plugins/replacement.js";
87
import { openNextResolvePlugin } from "../plugins/resolve.js";
98
import * as buildHelper from "./helper.js";
9+
import { installDependencies } from "./installDeps.js";
1010

1111
const require = createRequire(import.meta.url);
1212

@@ -108,29 +108,12 @@ export async function createImageOptimizationBundle(
108108
// Target should be same as used by Lambda, see https://github.com/sst/sst/blob/ca6f763fdfddd099ce2260202d0ce48c72e211ea/packages/sst/src/constructs/NextjsSite.ts#L114
109109
// For SHARP_IGNORE_GLOBAL_LIBVIPS see: https://github.com/lovell/sharp/blob/main/docs/install.md#aws-lambda
110110

111-
const nodeOutputPath = path.resolve(outputPath);
112111
const sharpVersion = process.env.SHARP_VERSION ?? "0.32.6";
113112

114-
const arch = config.imageOptimization?.arch ?? "arm64";
115-
const nodeVersion = config.imageOptimization?.nodeVersion ?? "18";
116-
117-
//check if we are running in Windows environment then set env variables accordingly.
118-
try {
119-
cp.execSync(
120-
// We might want to change the arch args to cpu args, it seems to be the documented way
121-
`npm install --arch=${arch} --platform=linux --target=${nodeVersion} --libc=glibc --prefix="${nodeOutputPath}" sharp@${sharpVersion}`,
122-
{
123-
stdio: "pipe",
124-
cwd: appPath,
125-
env: {
126-
...process.env,
127-
SHARP_IGNORE_GLOBAL_LIBVIPS: "1",
128-
},
129-
},
130-
);
131-
} catch (e: any) {
132-
logger.error(e.stdout.toString());
133-
logger.error(e.stderr.toString());
134-
logger.error("Failed to install sharp.");
135-
}
113+
installDependencies(
114+
outputPath,
115+
config.imageOptimization?.install ?? {
116+
packages: [`sharp@${sharpVersion}`],
117+
},
118+
);
136119
}

packages/open-next/src/build/createMiddleware.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import logger from "../logger.js";
55
import { type MiddlewareManifest } from "../types/next-types.js";
66
import { buildEdgeBundle } from "./edge/createEdgeBundle.js";
77
import * as buildHelper from "./helper.js";
8+
import { installDependencies } from "./installDeps.js";
89

910
export async function createMiddleware(options: buildHelper.BuildOptions) {
1011
logger.info(`Bundling middleware function...`);
@@ -58,6 +59,8 @@ export async function createMiddleware(options: buildHelper.BuildOptions) {
5859
includeCache: config.dangerous?.enableCacheInterception,
5960
additionalExternals: config.edgeExternals,
6061
});
62+
63+
installDependencies(outputPath, config.middleware?.install);
6164
} else {
6265
await buildEdgeBundle({
6366
entrypoint: path.join(

packages/open-next/src/build/createRevalidationBundle.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import path from "node:path";
44
import logger from "../logger.js";
55
import { openNextResolvePlugin } from "../plugins/resolve.js";
66
import * as buildHelper from "./helper.js";
7+
import { installDependencies } from "./installDeps.js";
78

89
export async function createRevalidationBundle(
910
options: buildHelper.BuildOptions,
@@ -41,6 +42,8 @@ export async function createRevalidationBundle(
4142
options,
4243
);
4344

45+
installDependencies(outputPath, config.revalidate?.install);
46+
4447
// Copy over .next/prerender-manifest.json file
4548
fs.copyFileSync(
4649
path.join(appBuildOutputPath, ".next", "prerender-manifest.json"),

packages/open-next/src/build/createServerBundle.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { compileCache } from "./compileCache.js";
1717
import { copyTracedFiles } from "./copyTracedFiles.js";
1818
import { generateEdgeBundle } from "./edge/createEdgeBundle.js";
1919
import * as buildHelper from "./helper.js";
20+
import { installDependencies } from "./installDeps.js";
2021

2122
const require = createRequire(import.meta.url);
2223

@@ -267,6 +268,8 @@ async function generateBundle(
267268
addMonorepoEntrypoint(outputPath, packagePath);
268269
}
269270

271+
installDependencies(outputPath, fnOptions.install);
272+
270273
if (fnOptions.minify) {
271274
await minifyServerBundle(outputPath);
272275
}

packages/open-next/src/build/createWarmerBundle.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import path from "node:path";
44
import logger from "../logger.js";
55
import { openNextResolvePlugin } from "../plugins/resolve.js";
66
import * as buildHelper from "./helper.js";
7+
import { installDependencies } from "./installDeps.js";
78

89
export async function createWarmerBundle(options: buildHelper.BuildOptions) {
910
logger.info(`Bundling warmer function...`);
@@ -48,4 +49,6 @@ export async function createWarmerBundle(options: buildHelper.BuildOptions) {
4849
},
4950
options,
5051
);
52+
53+
installDependencies(outputPath, config.warmer?.install);
5154
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { execSync } from "child_process";
2+
import * as fs from "fs";
3+
import * as os from "os";
4+
import * as path from "path";
5+
import { InstallOptions } from "types/open-next";
6+
7+
import logger from "../logger.js";
8+
9+
export function installDependencies(
10+
outputDir: string,
11+
installOptions?: InstallOptions,
12+
) {
13+
try {
14+
if (!installOptions) {
15+
return;
16+
}
17+
const name = outputDir.split("/").pop();
18+
// First we create a tempDir
19+
const tempInstallDir = fs.mkdtempSync(
20+
path.join(os.tmpdir(), `open-next-install-${name}`),
21+
);
22+
logger.info(`Installing dependencies for ${name}...`);
23+
// We then need to run install in the tempDir
24+
// We don't install in the output dir directly because it could contain a package.json, and npm would then try to reinstall not complete deps from tracing the files
25+
const installCommand = `npm install --arch=${installOptions.arch ?? "arm64"} --platform=linux --target=${installOptions.nodeVersion ?? "18"} --libc=${installOptions.libc ?? "glibc"} ${installOptions.packages.join(" ")}`;
26+
execSync(installCommand, {
27+
stdio: "pipe",
28+
cwd: tempInstallDir,
29+
env: {
30+
...process.env,
31+
SHARP_IGNORE_GLOBAL_LIBVIPS: "1",
32+
},
33+
});
34+
35+
// Copy the node_modules to the outputDir
36+
fs.cpSync(
37+
path.join(tempInstallDir, "node_modules"),
38+
path.join(outputDir, "node_modules"),
39+
40+
{ recursive: true, force: true, dereference: true },
41+
);
42+
43+
// Cleanup tempDir
44+
fs.rmSync(tempInstallDir, { recursive: true, force: true });
45+
logger.info(`Dependencies installed for ${name}`);
46+
} catch (e: any) {
47+
logger.error(e.stdout.toString());
48+
logger.error("Could not install dependencies");
49+
}
50+
}

packages/open-next/src/types/open-next.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,31 @@ export interface OverrideOptions extends DefaultOverrideOptions {
184184
queue?: IncludedQueue | LazyLoadedOverride<Queue>;
185185
}
186186

187+
export interface InstallOptions {
188+
/**
189+
* List of packages to install
190+
* @example
191+
* ```ts
192+
* install: {
193+
* packages: ["sharp@0.32"]
194+
* }
195+
* ```
196+
*/
197+
packages: string[];
198+
/**
199+
* @default "arm64"
200+
*/
201+
arch?: "x64" | "arm64";
202+
/**
203+
* @default "18"
204+
*/
205+
nodeVersion?: "18" | "20" | "22";
206+
/**
207+
* @default "glibc"
208+
*/
209+
libc?: "glibc" | "musl";
210+
}
211+
187212
export interface DefaultFunctionOptions<
188213
E extends BaseEventOrResult = InternalEvent,
189214
R extends BaseEventOrResult = InternalResult,
@@ -202,6 +227,14 @@ export interface DefaultFunctionOptions<
202227
* Enable overriding the default lambda.
203228
*/
204229
override?: DefaultOverrideOptions<E, R>;
230+
231+
/**
232+
* Install options for the function.
233+
* This is used to install additional packages to this function.
234+
* For image optimization, it will install sharp by default.
235+
* @default undefined
236+
*/
237+
install?: InstallOptions;
205238
}
206239

207240
export interface FunctionOptions extends DefaultFunctionOptions {
@@ -318,15 +351,6 @@ export interface OpenNextConfig {
318351
* @default "s3"
319352
*/
320353
loader?: IncludedImageLoader | LazyLoadedOverride<ImageLoader>;
321-
/**
322-
* @default "arm64"
323-
*/
324-
arch?: "x64" | "arm64";
325-
/**
326-
* @default "18"
327-
*/
328-
329-
nodeVersion?: "18" | "20";
330354
};
331355

332356
/**

0 commit comments

Comments
 (0)