google-cloud-node
google-cloud-node copied to clipboard
`@google-cloud/tasks` 4.1.0 causes cloud_tasks_client_config.json `no such file or directory` (publish esm)
The following error happens with @google-cloud/tasks
after updating from 4.0.1 to 4.1.0:
Error: ENOENT: no such file or directory, open '/vercel/path0/fuu/node_modules/.pnpm/@[email protected][email protected]/node_modules/@google-cloud/tasks/build/esm/src/v2/cloud_tasks_client_config.json'
at Object.openSync (node:fs:603:3)
at Object.readFileSync (node:fs:471:35)
at 64300 (/var/task/fuu/.next/server/app/app/api/site/route.js:1:1998)
at t (/var/task/fuu/.next/server/webpack-runtime.js:1:143)
at __webpack_exec__ (/var/task/fuu/.next/server/app/app/api/route.js:57:72254)
at /var/task/fuu/.next/server/app/app/api/route.js:57:72374
at t.X (/var/task/fuu/.next/server/webpack-runtime.js:1:1285)
at /var/task/fuu/.next/server/app/app/api/route.js:57:72340
at Object.<anonymous> (/var/task/fuu/.next/server/app/app/api/route.js:57:72435)
at Module._compile (node:internal/modules/cjs/loader:1256:14) {
errno: -2,
syscall: 'open',
code: 'ENOENT',
path: '/vercel/path0/fuu/node_modules/.pnpm/@[email protected][email protected]/node_modules/@google-cloud/tasks/build/esm/src/v2/cloud_tasks_client_config.json',
page: '/app/api/sync'
}
This seems to be related to the only change with was made from from version 4.0.1 to version 4.1.0: https://github.com/googleapis/google-cloud-node/pull/4720
Environment details
- which product (packages/*):
@google-cloud/tasks
- Node.js version: 18
- npm version: pnpm
Steps to reproduce
As a workaround, I've republished the 'latest' tag as 4.0.1. This should have been released as a breaking change. Please re-install the package at latest, it should work.
Thanks. I already downgraded to version 4.0.1 and can confirm with that version it works again. Looking forward to a proper new version then :-)
Could I trouble you for the code that failed? Thank you in advance.
Hey @sofisl ,
sure. It creates a new task:
Edited afterwards: Added import line
import { CloudTasksClient } from "@google-cloud/tasks"
const tasksClient = new CloudTasksClient({
projectId: process.env.GCP_TASKS_PROJECT_ID,
credentials: {
client_email: process.env.GCP_TASKS_CLIENT_EMAIL,
private_key: process.env.GCP_TASKS_PRIVATE_KEY,
},
})
// ...
const taskBody = { full: body?.full === "yes" }
await tasksClient.createTask({
parent: process.env.GCP_TASKS_PARENT,
task: {
httpRequest: {
httpMethod: "POST",
url: "https://...<my-url-here-which-I-removed>",
// See https://github.com/googleapis/nodejs-tasks/issues/606#issuecomment-1194074190 why encoding is needed
body: Buffer.from(JSON.stringify(taskBody)).toString("base64"),
oidcToken: {
serviceAccountEmail: process.env.GCP_TASKS_ACCOUNT_EMAIL,
},
},
},
})
Thank you! Could you include how you import the library?
Hey @sofisl ,
import { CloudTasksClient } from "@google-cloud/tasks"
The application is a Next.js application. The package manager is pnpm and the build command next build
.
Having this issue after migration to 5.0 Reverting back to forced 4.0.1 fixes the issue
Downgrading fixed it. Well that's 7h of troubleshooting for you. Glad I found this thread!
2 hours of my life spent on being frustrated. but anyway, thanks!
The ESM refactor introduced a layer of indirection for importing the JSON files, replacing require()
with a combination of readFileSync()
with a path computed via an expression, which together prevent the JSON files from being picked up by bundler tracing and included when bundling using setups like Next.js.
Importing JSON without readFileSync()
is possible in latest Node.js but requires experimental JSON imports enabled in earlier versions. I attempted to experiment with module.createRequire()
for ESM but this didn't appear to fix tracing with @vercel/nft
(as used by Next.js). The ideal solution may well be to convert the JSON files to a javascript object export, which would enable them to be imported and bundled/traced as normal.
cc: @sofisl as I see this issue was closed as "completed" without context, but still persists (specifically broken bundled ESM builds). Thanks!
Closed this because at the time, the release was accidental, it should have been released as a breaking change. Reopening because it seems like it's still an issue with the 5.0.0 release.
@andyjy, if you had a minimal repo reproduction that would be awesome! We don't technically guarantee bundler performance, but if there's a fix that I can make in the code to make it work with bundlers, I'd be happy to play around with it.
Thanks @sofisl - fair request for MRE. Due to time constraints I'm going to stick with v4 for now - I did try creating a PR to fix but ran into the complications I mentioned above.
Note to my future self and anyone else that assuming node >= v17.5.0 it should be possible to work around using patch-package or similar to replace the indirect imports with modern import json from "./file.json" assert { type: "json" };
(Not sure this can be incorporated directly into this package while it currently supports Node >= 14).
@andyjy @wangii @AntQwanlity @Xennis @felixmpaulus if any of you have a sample repo to reproduce, that would be awesome. I'm very interested in figuring this out.
FWIW, I created a Next.js app with Cloud tasks 5.1.0, it works perfectly :/ https://github.com/sofisl/debug-tasks-next.js
Thanks @sofisl - to reproduce this issue in your example repo, we need to create a standalone build - this is what activates tracing in an attempt to create the minimum required build rather than including every file within node_modules
I've reproduced with your repo as follows:
- add
output: standalone
tonext.config.mjs
:
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -1,5 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
+ output: "standalone",
reactStrictMode: true,
};
-
generate the standalone build:
npx next build
-
run the standalone build:
node .next/standalone/server.js
-
open the index page in browser and observe the error in the server console output:
Error: ENOENT: no such file or directory, open '[...]/debug-tasks-next.js/.next/standalone/node_modules/@google-cloud/tasks/build/esm/src/v2/cloud_tasks_client_config.json'
-
additionally observe that Next.js successfully traces and copies the JSON file under the cjs build to
.next/standalone/node_modules/@google-cloud/tasks/build/cjs/src/v2/cloud_tasks_client_config.json
- but then imports from the esm folder, which lacks the json file.
You'll see in the Next.js docs linked above that Next.js apparently supports manual inclusion of incorrectly omitted files; I haven't managed to get this working (didn't try super hard) but it may be a viable workaround, albeit Next.js-specific.
Thanks, hope this helps your investigation!
@andyjy, I've just released 5.1.1 which should contain the fix for this. Could I trouble you to give it a try and see if it works?
Thanks @sofisl - unfortunately the issue persists with 5.1.1 (including following the instructions above with your reproduction repo)
Same for esbuild in our case. The issue appeared in since 4.1.0 and still occurs with 5.1.1
const resolveFfmpegPlugin = {
name: 'resolveFfmpeg',
setup(build) {
build.onResolve({ filter: /lib-cov\/fluent-ffmpeg/ }, (args) => {
// fix https://github.com/fluent-ffmpeg/node-fluent-ffmpeg/issues/573
const actualPath = join(args.resolveDir, 'lib', 'fluent-ffmpeg.js');
return { path: actualPath };
});
},
};
const sourceMapPlugin = {
name: 'excludeVendorFromSourceMap',
setup(build) {
build.onLoad({ filter: /node_modules/ }, (args) => {
if (!args.path.endsWith('.json')) {
return {
contents: `${readFileSync(args.path, 'utf8')}\
\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==`,
loader: 'default',
};
}
return undefined;
});
},
};
const { metafile } = await esbuild.build({
entryPoints: [appPath],
outfile: targetFilePath,
format: 'esm',
bundle: true,
minify: true,
target: 'node20',
platform: 'node',
sourcemap: 'linked',
sourcesContent: false,
metafile: true,
legalComments: 'external',
loader: { '.ts': 'ts', '.js': 'js', '.node': 'copy', '.json': 'copy' },
banner: {
js: `
import path from 'path'; import { fileURLToPath } from 'url';
import { createRequire as topLevelCreateRequire } from 'module';
const require = topLevelCreateRequire(import.meta.url);
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
`,
},
plugins: [resolveFfmpegPlugin, sourceMapPlugin],
});
I've submitted a bug to Next, I can confirm it's still happening but I don't know why Next isn't copying over the files.
In the meantime, I found a workaround. The docs say:
There are some cases in which Next.js might fail to include required files, or might incorrectly include unused files. In those cases, you can leverage experimental.outputFileTracingExcludes and experimental.outputFileTracingIncludes respectively in next.config.js
With that, I was able to get Next to copy over the files using this configuration in next.config.mjs:
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
output: "standalone",
reactStrictMode: true,
experimental: {
outputFileTracingIncludes: {
'/': ['./node_modules/@google-cloud/tasks/build/esm/src/**/*.json'],
},
}
};
export default nextConfig;
Hope this helps!
@sofisl
Just to clarify, I only have this issue with turborepo (regardless of using yarn, npm or pnpm).
I created a small reproducible example here: https://github.com/ollebergkvist/turborepo-google-cloud-tasks-issue
pnpm install && cd apps/next-app && pnpm build
I'm having the issue, setup is pnpm 9 workspace + turbo 😬 rolled back to 4.0.1 and it works, anything above doesn't
@sofisl
After upgrading to the latest Next version, we now have the bug with yarn in the repo that was working previously (the one that is not a turborepo).
Did you open a github issue for this on Vercel? In that case can you please share the link so I can track the status please.
Many thanks in advance!
I have a version of this issue that's a little different but I think it's the same issue. My app is not a next.js application but I'm using a different library from vercel (makers of next.js), @vercel/ncc
. I'll add my details here on this thread, in the hopes it helps the thread overall:
I tried upgrading google-cloud/tasks from 4.0.1 to the current latest, 5.3. I downgraded back down to 4.0.1 because of this. I think the issue would've begun in version 4.1, as seen by others in this thread.
The summary is that ncc
is not picking up this cloud_tasks_client_config.json
file when transpiling our TS down to JS.
What I think is happening in the 4.0.1 version of google-cloud/tasks, it refers to this json file in a straightforward way that ncc's static analysis can find. The result is that ncc inlines the contents of the json file into the transpiled js. In the newer version of google-cloud/tasks (again, I used 5.3, but I think this began in 4.1), the reference to the json file is more dynamic / less straightforward, and ncc does not pick it up. The file's contents are not inlined into the transpiled js.
Here is how the file is referenced in 4.0.1, which seems straightforward:
const gapicConfig = require("./cloud_tasks_client_config.json");
And here is how it is in 5.3, the latest version:
const dirname = path.dirname(fileURLToPath(import.meta.url));
...
const gapicConfig = getJSON(path.join(dirname, 'cloud_tasks_client_config.json'));
I suspect (but do not really know) that it's that fileURLToPath(import.meta.url)
that is throwing things off.
(A comment above describes this as well, I think, or something very similar.)
Perhaps it's possible for the lib to alter how it references this json, since the newer/dynamic way seems to have side effects for multiple users?
Also, I noticed that slightly higher up in the cloud_tasks_client.ts, here, the lib imports the json file directly into memory? Maybe this can be done everywhere, to solve this issue?
Thank you.
Any update on this? My SolidStart + Turborepo + Cloud Run project is affected by this issue too.
Here's what I have after doing some digging/answering some questions:
- @ollebergkvist, thanks for your reproduction repo. I was able to reproduce the issue successfully. During my investigation I deleted the .pnpm-lock.yaml file and re-installed it. That successfully installed the missing file, i.e.:
However, after running
cd apps/next-app && pnpm build
I still get:
Collecting page data ...Error: Cannot find module '/Users/sofialeon/turborepo-google-cloud-tasks-issue/node_modules/.pnpm/@[email protected]/node_modules/@google-cloud/tasks/build/esm/src/v2/cloud_tasks_client_config.json'
I can confirm the file exists
This is a pretty clear Next.js issue. I don't know why it cannot see the file, perhaps it has something to do with turborepo. If you could submit this bug within Next.js that would be greatly appreciated.
For the time being, I've submitted this bug, which seems related (and perhaps would fix this issue as well): https://github.com/vercel/next.js/issues/63368
@danbrauer, the reason we made this change was to support ESM. I don't see any other way of supporting this option in ESM.
Also, @danbrauer you're right that we are importing it into memory in this line! Without it, we wouldn't be able to parse the JSON later. But also, as you can see, the JSON file is imported correctly in .pnpm and turbo - for some reason, next.js doesn't want to pick it up.
Since ESM is the future, I'd love for this issue to be brought up in the next.js community, since I think this support will be needed as we move towards the future.