@opennextjs/cloudflare 0.4.3 → 0.4.4
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/api/cloudflare-context.js +11 -0
- package/dist/cli/build/build.js +4 -1
- package/dist/cli/build/bundle-server.js +8 -10
- package/dist/cli/build/patches/plugins/optional-deps.d.ts +15 -0
- package/dist/cli/build/patches/plugins/optional-deps.js +52 -0
- package/dist/cli/build/patches/plugins/require-page.d.ts +1 -1
- package/dist/cli/build/patches/plugins/require-page.js +1 -1
- package/dist/cli/build/patches/plugins/require.d.ts +1 -1
- package/dist/cli/build/patches/plugins/require.js +2 -2
- package/dist/cli/build/patches/plugins/wrangler-external.d.ts +1 -1
- package/dist/cli/build/patches/plugins/wrangler-external.js +1 -1
- package/dist/cli/build/utils/version.d.ts +4 -0
- package/dist/cli/build/utils/version.js +12 -0
- package/package.json +2 -2
- package/dist/cli/build/patches/ast/optional-deps.d.ts +0 -20
- package/dist/cli/build/patches/ast/optional-deps.js +0 -44
- package/dist/cli/build/patches/ast/optional-deps.spec.d.ts +0 -1
- package/dist/cli/build/patches/ast/optional-deps.spec.js +0 -135
|
@@ -15,6 +15,17 @@ export function getCloudflareContext() {
|
|
|
15
15
|
const global = globalThis;
|
|
16
16
|
const cloudflareContext = global[cloudflareContextSymbol];
|
|
17
17
|
if (!cloudflareContext) {
|
|
18
|
+
// For SSG Next.js creates (jest) workers that run in parallel, those don't get the current global
|
|
19
|
+
// state so they can't get access to the cloudflare context, unfortunately there isn't anything we
|
|
20
|
+
// can do about this, so the only solution is to error asking the developer to opt-out of SSG
|
|
21
|
+
// Next.js sets globalThis.__NEXT_DATA__.nextExport to true for the worker, so we can use that to detect
|
|
22
|
+
// that the route is being SSG'd (source: https://github.com/vercel/next.js/blob/4e394608423/packages/next/src/export/worker.ts#L55-L57)
|
|
23
|
+
if (global.__NEXT_DATA__?.nextExport === true) {
|
|
24
|
+
throw new Error(`\n\nERROR: \`getCloudflareContext\` has been called in a static route` +
|
|
25
|
+
` that is not allowed, please either avoid calling \`getCloudflareContext\`` +
|
|
26
|
+
` in the route or make the route non static (for example by exporting the` +
|
|
27
|
+
` \`dynamic\` route segment config set to \`'force-dynamic'\`.\n`);
|
|
28
|
+
}
|
|
18
29
|
// the cloudflare context is initialized by the worker and is always present in production/preview
|
|
19
30
|
// during local development (`next dev`) it might be missing only if the developers hasn't called
|
|
20
31
|
// the `initOpenNextCloudflareForDev` function in their Next.js config file
|
package/dist/cli/build/build.js
CHANGED
|
@@ -13,6 +13,7 @@ import { compileEnvFiles } from "./open-next/compile-env-files.js";
|
|
|
13
13
|
import { copyCacheAssets } from "./open-next/copyCacheAssets.js";
|
|
14
14
|
import { createServerBundle } from "./open-next/createServerBundle.js";
|
|
15
15
|
import { createOpenNextConfigIfNotExistent, createWranglerConfigIfNotExistent, ensureCloudflareConfig, } from "./utils/index.js";
|
|
16
|
+
import { getVersion } from "./utils/version.js";
|
|
16
17
|
/**
|
|
17
18
|
* Builds the application in a format that can be passed to workerd
|
|
18
19
|
*
|
|
@@ -40,7 +41,9 @@ export async function build(projectOpts) {
|
|
|
40
41
|
logger.info(`App directory: ${options.appPath}`);
|
|
41
42
|
buildHelper.printNextjsVersion(options);
|
|
42
43
|
ensureNextjsVersionSupported(options);
|
|
43
|
-
|
|
44
|
+
const { aws, cloudflare } = getVersion();
|
|
45
|
+
logger.info(`@opennextjs/cloudflare version: ${cloudflare}`);
|
|
46
|
+
logger.info(`@opennextjs/aws version: ${aws}`);
|
|
44
47
|
if (projectOpts.skipNextBuild) {
|
|
45
48
|
logger.warn("Skipping Next.js build");
|
|
46
49
|
}
|
|
@@ -2,16 +2,15 @@ import fs from "node:fs";
|
|
|
2
2
|
import { readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { Lang, parse } from "@ast-grep/napi";
|
|
6
5
|
import { getPackagePath } from "@opennextjs/aws/build/helper.js";
|
|
7
6
|
import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js";
|
|
8
7
|
import { build } from "esbuild";
|
|
9
|
-
import { patchOptionalDependencies } from "./patches/ast/optional-deps.js";
|
|
10
8
|
import { patchVercelOgLibrary } from "./patches/ast/patch-vercel-og-library.js";
|
|
11
9
|
import * as patches from "./patches/index.js";
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
10
|
+
import { handleOptionalDependencies } from "./patches/plugins/optional-deps.js";
|
|
11
|
+
import { fixRequire } from "./patches/plugins/require.js";
|
|
12
|
+
import { inlineRequirePagePlugin } from "./patches/plugins/require-page.js";
|
|
13
|
+
import { setWranglerExternal } from "./patches/plugins/wrangler-external.js";
|
|
15
14
|
import { normalizePath, patchCodeWithValidations } from "./utils/index.js";
|
|
16
15
|
/** The dist directory of the Cloudflare adapter package */
|
|
17
16
|
const packageDistDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
@@ -56,8 +55,9 @@ export async function bundleServer(buildOpts) {
|
|
|
56
55
|
inlineRequirePagePlugin(buildOpts),
|
|
57
56
|
setWranglerExternal(),
|
|
58
57
|
fixRequire(),
|
|
58
|
+
handleOptionalDependencies(optionalDependencies),
|
|
59
59
|
],
|
|
60
|
-
external: ["./middleware/handler.mjs"
|
|
60
|
+
external: ["./middleware/handler.mjs"],
|
|
61
61
|
alias: {
|
|
62
62
|
// Note: we apply an empty shim to next/dist/compiled/ws because it generates two `eval`s:
|
|
63
63
|
// eval("require")("bufferutil");
|
|
@@ -74,7 +74,7 @@ export async function bundleServer(buildOpts) {
|
|
|
74
74
|
},
|
|
75
75
|
define: {
|
|
76
76
|
// config file used by Next.js, see: https://github.com/vercel/next.js/blob/68a7128/packages/next/src/build/utils.ts#L2137-L2139
|
|
77
|
-
"process.env.__NEXT_PRIVATE_STANDALONE_CONFIG":
|
|
77
|
+
"process.env.__NEXT_PRIVATE_STANDALONE_CONFIG": JSON.stringify(JSON.stringify(nextConfig)),
|
|
78
78
|
// Next.js tried to access __dirname so we need to define it
|
|
79
79
|
__dirname: '""',
|
|
80
80
|
// Note: we need the __non_webpack_require__ variable declared as it is used by next-server:
|
|
@@ -168,9 +168,7 @@ export async function updateWorkerBundledCode(workerOutputFile, buildOpts) {
|
|
|
168
168
|
(code) => code.replace('require.resolve("./cache.cjs")', '"unused"'),
|
|
169
169
|
],
|
|
170
170
|
]);
|
|
171
|
-
|
|
172
|
-
const { edits } = patchOptionalDependencies(bundle, optionalDependencies);
|
|
173
|
-
await writeFile(workerOutputFile, bundle.commitEdits(edits));
|
|
171
|
+
await writeFile(workerOutputFile, patchedCode);
|
|
174
172
|
}
|
|
175
173
|
function createFixRequiresESBuildPlugin(options) {
|
|
176
174
|
return {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESBuild plugin to handle optional dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Optional dependencies might be installed by the application to support optional features.
|
|
5
|
+
*
|
|
6
|
+
* When an optional dependency is installed, it must be inlined in the bundle.
|
|
7
|
+
* When it is not installed, the plugin swaps it for a throwing implementation.
|
|
8
|
+
*
|
|
9
|
+
* The plugin uses ESBuild built-in resolution to check if the dependency is installed.
|
|
10
|
+
*/
|
|
11
|
+
import type { PluginBuild } from "esbuild";
|
|
12
|
+
export declare function handleOptionalDependencies(dependencies: string[]): {
|
|
13
|
+
name: string;
|
|
14
|
+
setup: (build: PluginBuild) => Promise<void>;
|
|
15
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESBuild plugin to handle optional dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Optional dependencies might be installed by the application to support optional features.
|
|
5
|
+
*
|
|
6
|
+
* When an optional dependency is installed, it must be inlined in the bundle.
|
|
7
|
+
* When it is not installed, the plugin swaps it for a throwing implementation.
|
|
8
|
+
*
|
|
9
|
+
* The plugin uses ESBuild built-in resolution to check if the dependency is installed.
|
|
10
|
+
*/
|
|
11
|
+
export function handleOptionalDependencies(dependencies) {
|
|
12
|
+
// Regex matching either a full module ("module") or a prefix ("module/...")
|
|
13
|
+
const filter = new RegExp(`^(${dependencies.flatMap((name) => [`${name}$`, String.raw `${name}/`]).join("|")})`);
|
|
14
|
+
const name = "optional-deps";
|
|
15
|
+
const marker = {};
|
|
16
|
+
const nsMissingDependency = `${name}-missing-dependency`;
|
|
17
|
+
return {
|
|
18
|
+
name,
|
|
19
|
+
setup: async (build) => {
|
|
20
|
+
build.onResolve({ filter }, async ({ path, pluginData, ...options }) => {
|
|
21
|
+
// Use ESBuild to resolve the dependency.
|
|
22
|
+
// Because the plugin asks ESBuild to resolve the path we just received,
|
|
23
|
+
// ESBuild will ask this plugin again.
|
|
24
|
+
// We use a marker in the pluginData to break the loop.
|
|
25
|
+
if (pluginData === marker) {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
const result = await build.resolve(path, {
|
|
29
|
+
...options,
|
|
30
|
+
pluginData: marker,
|
|
31
|
+
});
|
|
32
|
+
// ESBuild reports error when the dependency is not installed.
|
|
33
|
+
// In such a case the OnLoad hook will inline a throwing implementation.
|
|
34
|
+
if (result.errors.length > 0) {
|
|
35
|
+
return {
|
|
36
|
+
path: `/${path}`,
|
|
37
|
+
namespace: nsMissingDependency,
|
|
38
|
+
pluginData: { name: path },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// Returns ESBuild resolution information when the dependency is installed.
|
|
42
|
+
return result;
|
|
43
|
+
});
|
|
44
|
+
// Replaces missing dependency with a throwing implementation.
|
|
45
|
+
build.onLoad({ filter: /.*/, namespace: nsMissingDependency }, ({ pluginData }) => {
|
|
46
|
+
return {
|
|
47
|
+
contents: `throw new Error('Missing optional dependency "${pluginData.name}"')`,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type BuildOptions } from "@opennextjs/aws/build/helper.js";
|
|
2
2
|
import type { PluginBuild } from "esbuild";
|
|
3
|
-
export
|
|
3
|
+
export declare function inlineRequirePagePlugin(buildOpts: BuildOptions): {
|
|
4
4
|
name: string;
|
|
5
5
|
setup: (build: PluginBuild) => Promise<void>;
|
|
6
6
|
};
|
|
@@ -4,7 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { getPackagePath } from "@opennextjs/aws/build/helper.js";
|
|
5
5
|
import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js";
|
|
6
6
|
import { patchCode } from "../ast/util.js";
|
|
7
|
-
export
|
|
7
|
+
export function inlineRequirePagePlugin(buildOpts) {
|
|
8
8
|
return {
|
|
9
9
|
name: "inline-require-page",
|
|
10
10
|
setup: async (build) => {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
|
-
export
|
|
2
|
+
export function fixRequire() {
|
|
3
3
|
return {
|
|
4
4
|
name: "fix-require",
|
|
5
5
|
setup: async (build) => {
|
|
6
|
-
build.onLoad({ filter:
|
|
6
|
+
build.onLoad({ filter: /\.(js|mjs|cjs|jsx|ts|tsx)$/ }, async ({ path }) => {
|
|
7
7
|
let contents = await fs.readFile(path, "utf-8");
|
|
8
8
|
// `eval(...)` is not supported by workerd.
|
|
9
9
|
contents = contents.replaceAll(`eval("require")`, "require");
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* ref: https://developers.cloudflare.com/workers/wrangler/bundling/
|
|
15
15
|
*/
|
|
16
16
|
import type { PluginBuild } from "esbuild";
|
|
17
|
-
export
|
|
17
|
+
export declare function setWranglerExternal(): {
|
|
18
18
|
name: string;
|
|
19
19
|
setup: (build: PluginBuild) => Promise<void>;
|
|
20
20
|
};
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* ref: https://developers.cloudflare.com/workers/wrangler/bundling/
|
|
15
15
|
*/
|
|
16
16
|
import { dirname, resolve } from "node:path";
|
|
17
|
-
export
|
|
17
|
+
export function setWranglerExternal() {
|
|
18
18
|
return {
|
|
19
19
|
name: "wrangler-externals",
|
|
20
20
|
setup: async (build) => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
export function getVersion() {
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
7
|
+
const pkgJson = require(join(__dirname, "../../../../package.json"));
|
|
8
|
+
return {
|
|
9
|
+
cloudflare: pkgJson.version,
|
|
10
|
+
aws: pkgJson.dependencies["@opennextjs/aws"],
|
|
11
|
+
};
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opennextjs/cloudflare",
|
|
3
3
|
"description": "Cloudflare builder for next apps",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"opennextjs-cloudflare": "dist/cli/index.js"
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@ast-grep/napi": "^0.34.1",
|
|
65
65
|
"@dotenvx/dotenvx": "1.31.0",
|
|
66
|
-
"@opennextjs/aws": "https://pkg.pr.new/@opennextjs/aws@
|
|
66
|
+
"@opennextjs/aws": "https://pkg.pr.new/@opennextjs/aws@722",
|
|
67
67
|
"enquirer": "^2.4.1",
|
|
68
68
|
"glob": "^11.0.0",
|
|
69
69
|
"ts-morph": "^23.0.0",
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type SgNode } from "@ast-grep/napi";
|
|
2
|
-
/**
|
|
3
|
-
* Handles optional dependencies.
|
|
4
|
-
*
|
|
5
|
-
* A top level `require(optionalDep)` would throw when the dep is not installed.
|
|
6
|
-
*
|
|
7
|
-
* So we wrap `require(optionalDep)` in a try/catch (if not already present).
|
|
8
|
-
*/
|
|
9
|
-
export declare function buildOptionalDepRule(dependencies: string[]): string;
|
|
10
|
-
/**
|
|
11
|
-
* Wraps requires for passed dependencies in a `try ... catch`.
|
|
12
|
-
*
|
|
13
|
-
* @param root AST root node
|
|
14
|
-
* @param dependencies List of dependencies to wrap
|
|
15
|
-
* @returns matches and edits, see `applyRule`
|
|
16
|
-
*/
|
|
17
|
-
export declare function patchOptionalDependencies(root: SgNode, dependencies: string[]): {
|
|
18
|
-
edits: import("@ast-grep/napi").Edit[];
|
|
19
|
-
matches: SgNode<import("@ast-grep/napi/types/staticTypes.js").TypesMap, import("@ast-grep/napi/types/staticTypes.js").Kinds<import("@ast-grep/napi/types/staticTypes.js").TypesMap>>[];
|
|
20
|
-
};
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { applyRule } from "./util.js";
|
|
2
|
-
/**
|
|
3
|
-
* Handles optional dependencies.
|
|
4
|
-
*
|
|
5
|
-
* A top level `require(optionalDep)` would throw when the dep is not installed.
|
|
6
|
-
*
|
|
7
|
-
* So we wrap `require(optionalDep)` in a try/catch (if not already present).
|
|
8
|
-
*/
|
|
9
|
-
export function buildOptionalDepRule(dependencies) {
|
|
10
|
-
// Build a regexp matching either
|
|
11
|
-
// - the full packages names, i.e. `package`
|
|
12
|
-
// - subpaths in the package, i.e. `package/...`
|
|
13
|
-
const regex = `^(${dependencies.join("|")})(/|$)`;
|
|
14
|
-
return `
|
|
15
|
-
rule:
|
|
16
|
-
pattern: $$$LHS = require($$$REQ)
|
|
17
|
-
has:
|
|
18
|
-
pattern: $MOD
|
|
19
|
-
kind: string_fragment
|
|
20
|
-
stopBy: end
|
|
21
|
-
regex: ${regex}
|
|
22
|
-
not:
|
|
23
|
-
inside:
|
|
24
|
-
kind: try_statement
|
|
25
|
-
stopBy: end
|
|
26
|
-
|
|
27
|
-
fix: |-
|
|
28
|
-
try {
|
|
29
|
-
$$$LHS = require($$$REQ);
|
|
30
|
-
} catch {
|
|
31
|
-
throw new Error('The optional dependency "$MOD" is not installed');
|
|
32
|
-
}
|
|
33
|
-
`;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Wraps requires for passed dependencies in a `try ... catch`.
|
|
37
|
-
*
|
|
38
|
-
* @param root AST root node
|
|
39
|
-
* @param dependencies List of dependencies to wrap
|
|
40
|
-
* @returns matches and edits, see `applyRule`
|
|
41
|
-
*/
|
|
42
|
-
export function patchOptionalDependencies(root, dependencies) {
|
|
43
|
-
return applyRule(buildOptionalDepRule(dependencies), root);
|
|
44
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { buildOptionalDepRule } from "./optional-deps.js";
|
|
3
|
-
import { patchCode } from "./util.js";
|
|
4
|
-
describe("optional dependecy", () => {
|
|
5
|
-
it('should wrap a top-level require("caniuse-lite") in a try-catch', () => {
|
|
6
|
-
const code = `t = require("caniuse-lite");`;
|
|
7
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite"]))).toMatchInlineSnapshot(`
|
|
8
|
-
"try {
|
|
9
|
-
t = require("caniuse-lite");
|
|
10
|
-
} catch {
|
|
11
|
-
throw new Error('The optional dependency "caniuse-lite" is not installed');
|
|
12
|
-
};"
|
|
13
|
-
`);
|
|
14
|
-
});
|
|
15
|
-
it('should wrap a top-level require("caniuse-lite/data") in a try-catch', () => {
|
|
16
|
-
const code = `t = require("caniuse-lite/data");`;
|
|
17
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite"]))).toMatchInlineSnapshot(`
|
|
18
|
-
"try {
|
|
19
|
-
t = require("caniuse-lite/data");
|
|
20
|
-
} catch {
|
|
21
|
-
throw new Error('The optional dependency "caniuse-lite/data" is not installed');
|
|
22
|
-
};"
|
|
23
|
-
`);
|
|
24
|
-
});
|
|
25
|
-
it('should wrap e.exports = require("caniuse-lite") in a try-catch', () => {
|
|
26
|
-
const code = 'e.exports = require("caniuse-lite");';
|
|
27
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite"]))).toMatchInlineSnapshot(`
|
|
28
|
-
"try {
|
|
29
|
-
e.exports = require("caniuse-lite");
|
|
30
|
-
} catch {
|
|
31
|
-
throw new Error('The optional dependency "caniuse-lite" is not installed');
|
|
32
|
-
};"
|
|
33
|
-
`);
|
|
34
|
-
});
|
|
35
|
-
it('should wrap module.exports = require("caniuse-lite") in a try-catch', () => {
|
|
36
|
-
const code = 'module.exports = require("caniuse-lite");';
|
|
37
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite"]))).toMatchInlineSnapshot(`
|
|
38
|
-
"try {
|
|
39
|
-
module.exports = require("caniuse-lite");
|
|
40
|
-
} catch {
|
|
41
|
-
throw new Error('The optional dependency "caniuse-lite" is not installed');
|
|
42
|
-
};"
|
|
43
|
-
`);
|
|
44
|
-
});
|
|
45
|
-
it('should wrap exports.foo = require("caniuse-lite") in a try-catch', () => {
|
|
46
|
-
const code = 'exports.foo = require("caniuse-lite");';
|
|
47
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite"]))).toMatchInlineSnapshot(`
|
|
48
|
-
"try {
|
|
49
|
-
exports.foo = require("caniuse-lite");
|
|
50
|
-
} catch {
|
|
51
|
-
throw new Error('The optional dependency "caniuse-lite" is not installed');
|
|
52
|
-
};"
|
|
53
|
-
`);
|
|
54
|
-
});
|
|
55
|
-
it('should not wrap require("lodash") in a try-catch', () => {
|
|
56
|
-
const code = 't = require("lodash");';
|
|
57
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite"]))).toMatchInlineSnapshot(`"t = require("lodash");"`);
|
|
58
|
-
});
|
|
59
|
-
it('should not wrap require("other-module") if it does not match caniuse-lite regex', () => {
|
|
60
|
-
const code = 't = require("other-module");';
|
|
61
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite"]))).toMatchInlineSnapshot(`"t = require("other-module");"`);
|
|
62
|
-
});
|
|
63
|
-
it("should not wrap a require() call already inside a try-catch", () => {
|
|
64
|
-
const code = `
|
|
65
|
-
try {
|
|
66
|
-
t = require("caniuse-lite");
|
|
67
|
-
} catch {}
|
|
68
|
-
`;
|
|
69
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite"]))).toMatchInlineSnapshot(`
|
|
70
|
-
"try {
|
|
71
|
-
t = require("caniuse-lite");
|
|
72
|
-
} catch {}
|
|
73
|
-
"
|
|
74
|
-
`);
|
|
75
|
-
});
|
|
76
|
-
it("should handle require with subpath and not wrap if already in try-catch", () => {
|
|
77
|
-
const code = `
|
|
78
|
-
try {
|
|
79
|
-
t = require("caniuse-lite/path");
|
|
80
|
-
} catch {}
|
|
81
|
-
`;
|
|
82
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite"]))).toMatchInlineSnapshot(`
|
|
83
|
-
"try {
|
|
84
|
-
t = require("caniuse-lite/path");
|
|
85
|
-
} catch {}
|
|
86
|
-
"
|
|
87
|
-
`);
|
|
88
|
-
});
|
|
89
|
-
it("should handle multiple dependencies", () => {
|
|
90
|
-
const code = `
|
|
91
|
-
t1 = require("caniuse-lite");
|
|
92
|
-
t2 = require("caniuse-lite/path");
|
|
93
|
-
t3 = require("jimp");
|
|
94
|
-
t4 = require("jimp/path");
|
|
95
|
-
`;
|
|
96
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite", "jimp"]))).toMatchInlineSnapshot(`
|
|
97
|
-
"try {
|
|
98
|
-
t1 = require("caniuse-lite");
|
|
99
|
-
} catch {
|
|
100
|
-
throw new Error('The optional dependency "caniuse-lite" is not installed');
|
|
101
|
-
};
|
|
102
|
-
try {
|
|
103
|
-
t2 = require("caniuse-lite/path");
|
|
104
|
-
} catch {
|
|
105
|
-
throw new Error('The optional dependency "caniuse-lite/path" is not installed');
|
|
106
|
-
};
|
|
107
|
-
try {
|
|
108
|
-
t3 = require("jimp");
|
|
109
|
-
} catch {
|
|
110
|
-
throw new Error('The optional dependency "jimp" is not installed');
|
|
111
|
-
};
|
|
112
|
-
try {
|
|
113
|
-
t4 = require("jimp/path");
|
|
114
|
-
} catch {
|
|
115
|
-
throw new Error('The optional dependency "jimp/path" is not installed');
|
|
116
|
-
};
|
|
117
|
-
"
|
|
118
|
-
`);
|
|
119
|
-
});
|
|
120
|
-
it("should not update partial matches", () => {
|
|
121
|
-
const code = `
|
|
122
|
-
t1 = require("before-caniuse-lite");
|
|
123
|
-
t2 = require("before-caniuse-lite/path");
|
|
124
|
-
t3 = require("caniuse-lite-after");
|
|
125
|
-
t4 = require("caniuse-lite-after/path");
|
|
126
|
-
`;
|
|
127
|
-
expect(patchCode(code, buildOptionalDepRule(["caniuse-lite"]))).toMatchInlineSnapshot(`
|
|
128
|
-
"t1 = require("before-caniuse-lite");
|
|
129
|
-
t2 = require("before-caniuse-lite/path");
|
|
130
|
-
t3 = require("caniuse-lite-after");
|
|
131
|
-
t4 = require("caniuse-lite-after/path");
|
|
132
|
-
"
|
|
133
|
-
`);
|
|
134
|
-
});
|
|
135
|
-
});
|