keystone: Starting or Building Keystone with NODE_ENV set production fails.

Please add steps to reproduce the problem

  • Scaffold a new Keystonejs app.
  • Install dotenv or a similar tool
  • inside keysone.ts file, import dotenv import 'dotenv/config';
  • set NODE_ENV=production in .env file
  • Try building the project.

Please describe what you expected to happen

It should build successfully. It builds in development, testing, and staging. It builds even when NODE_ENV is undefined. But only fails in production mode.

Please add any screenshots if possible

image

Please add contextual information such as your node version (node -v), or the web browser you used

Tried on NODE v16, v18, and v20 (using nvm).

About this issue

  • Original URL
  • State: open
  • Created 10 months ago
  • Reactions: 2
  • Comments: 18 (11 by maintainers)

Most upvoted comments

@dcousens I looked into it a bit, and the key information was hidden in the plain sight

at Object.getAdminMetaForRelationshipField ([...]/@keystone-6/core/dist/create-admin-meta-5d6c7c4d.cjs.prod.js:154:11)
at Object.getAdminMeta ([...]/@keystone-6/core/fields/dist/keystone-6-core-fields.cjs.prod.js:2882:45)
at Object.createAdminMeta [...]/@keystone-6/core/dist/create-admin-meta-d9f6d1a4.cjs.dev.js:142:245)

Notice how initially node is using .dev.js bundle and later it is switching to .prod.js bundle.

So here is what I believe is happening:

  1. Unless you have NODE_ENV specified in your initial env, build process starts with NODE_ENV undefined. By default node assumes development environment and selects .dev.js bundle.
  2. On build::getBuiltKeystoneConfiguration it dynamically loads .keystone/config.js, which in turn makes dotenv set NODE_ENV to your value (production).
  3. Because all initial imports are already resolved, it keeps using them (.dev.js), but any new import will use .prod.js bundle.
  4. It just happens that create-admin-meta.ts is using global variable currentAdminMeta (proabably should be refactored) that gets initialized in .dev.js import, but then the same file gets re-imported from .prod.js and now this variable is undefined.
  5. Error happens

Additional (surprising) takeaway: Prisma is already using dotenv. Although keystone is not using prisma init, as far as I understand prisma client is reading from .env when creating instance anyway. .keystone/config.js already has dotenv code whether you want it or not. However because it is not executed on require call, there are no build problems.

@ttbarnes in a major release coming soon (as it will be a breaking change), we will be updating the behaviour of ui.isDisabled to omit the definition of the adminMeta GraphQL queries completely when true, this might be nearer to what you expect.

As recommended in https://github.com/keystonejs/keystone/pull/8773.

Interesting, I think we should keep this open

That’s exactly what I was doing. See the screenshot attached. Or the loom. But it was causing an error.

@dcousens I checked this and I can reproduce it. The key is to import dotenv before importing schema (otherwise error does not happen) and having NODE_ENV=production in .env Funnily enough if you use NODE_ENV=production yarn keystone build then it works fine (with and without dotenv). Also any other env loaded by dotenv seem to work just fine. Which leads me to believe this is somehow related to esbuild special treatment of NODE_ENV as per https://github.com/keystonejs/keystone/security/advisories/GHSA-25mx-2mxm-6343

@chukwumaijem if this is blocker for you (you use NODE_ENV checks for some other code), try adding NODE_ENV in the package.json script commands - "build": "NODE_ENV=production keystone build", "dev": "NODE_ENV=development keystone dev" etc.