Olivier Papineau
Olivier Papineau

Reputation: 23

Vite environment variables missing when building a React App with NX

I'm currently working on a monorepo project using NX and Vite. I have multiple .env files for our multiple deployment environments:

My problem is, when developing, I'm getting the environment variables as normal but when we build to deploy to our test environments, the bundle build succeeds but there is no trace of any environment variable in the sources. All env variables are prefixed with `VITE_` as indicated in the documentation.

Here is my vite.config.ts in app/<name>/src

import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
import dts from 'vite-plugin-dts'
import * as path from 'path'
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'

export default defineConfig(({ mode }) => {
  process.env = { ...process.env, ...loadEnv(mode, process.cwd()) }

  return {
    root: __dirname,
    ...(process.env.NODE_ENV === 'dev' || process.env.NODE_ENV === 'development'
      ? {
          define: {
            global: {},
          },
        }
      : {}),
    cacheDir: '../node_modules/.vite/api',

    plugins: [
      react(),
      nxViteTsPaths(),
      dts({
        entryRoot: 'src',
        tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'),
        skipDiagnostics: true,
      }),
    ],

    // Uncomment this if you are using workers.
    // worker: {
    //  plugins: [ nxViteTsPaths() ],
    // },

    // Configuration for building your library.
    // See: https://vitejs.dev/guide/build.html#library-mode
    build: {
      outDir: '../dist/api',
      reportCompressedSize: true,
      commonjsOptions: { transformMixedEsModules: true },
      entry: 'src/index.ts',
      name: 'api',
      fileName: 'index',
      formats: ['es', 'cjs'],
      external: ['react', 'react-dom', 'react/jsx-runtime'],
      lib: {
        entry: 'src/index.ts',
        name: 'api',
        fileName: 'index',
        formats: ['es', 'cjs'],
      },
      rollupOptions: {
        external: ["'react'", "'react-dom'", "'react/jsx-runtime'"],
      },
    },
  }
})

Here is my project.json in that same directory:

{
  "name": "n360-portal",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "apps/n360-portal/src",
  "projectType": "application",
  "targets": {
    "build": {
      "executor": "@nx/vite:build",
      "outputs": ["{options.outputPath}"],
      "defaultConfiguration": "production",
      "options": {
        "outputPath": "dist/apps/n360-portal"
      },
      "configurations": {
        "development": {
          "mode": "dev"
        },
        "production": {
          "mode": "prod"
        },
        "staging": {
          "mode": "stg"
        },
        "int": {
          "mode": "int"
        }
      }
    },
    "serve": {
      "executor": "@nx/vite:dev-server",
      "defaultConfiguration": "development",
      "options": {
        "buildTarget": "n360-portal:build"
      },
      "configurations": {
        "development": {
          "buildTarget": "n360-portal:build:development",
          "hmr": true,
          "mode": "dev"
        },
        "staging": {
          "buildTarget": "n360-portal:build:staging",
          "hmr": true,
          "mode": "stg"
        },
        "int": {
          "buildTarget": "n360-portal:build:int",
          "hmr": true,
          "mode": "int"
        },
        "production": {
          "buildTarget": "n360-portal:build:production",
          "hmr": true,
          "mode": "prod"
        }
      }
    },
    "preview": {
      "executor": "@nx/vite:preview-server",
      "defaultConfiguration": "development",
      "options": {
        "buildTarget": "n360-portal:build"
      },
      "configurations": {
        "development": {
          "buildTarget": "n360-portal:build:development"
        },
        "staging": {
          "buildTarget": "n360-portal:build:staging"
        },
        "int": {
          "buildTarget": "n360-portal:build:int"
        },
        "production": {
          "buildTarget": "n360-portal:build:production"
        }
      }
    },
    "test": {
      "executor": "@nx/vite:test",
      "outputs": ["{options.reportsDirectory}"],
      "options": {
        "passWithNoTests": true,
        "reportsDirectory": "../../coverage/apps/n360-portal"
      }
    },
    "lint": {
      "executor": "@nx/eslint:lint",
      "outputs": ["{options.outputFile}"]
    },
    "serve-static": {
      "executor": "@nx/web:file-server",
      "options": {
        "buildTarget": "n360-portal:build"
      }
    }
  },
  "tags": []
}

Here is our `bitbucket-pipelines.yml`

image: node:20

definitions:
  caches:
    pnpm: $BITBUCKET_CLONE_DIR/.pnpm-store
  steps:
    - step: &Build
        name: Build 
        caches:
          - node
          - pnpm
        script:
          - make install-deps-build
    - step: &Build-Deploy
        name: Build and deploy
        caches:
          - node
          - pnpm
        script:
          - make build-deploy
          - echo "VITE_API_URL=$VITE_API_URL" 
          - echo "VITE_DOCS_LINK=$VITE_DOCS_LINK" 
          - echo "VITE_STATUS_LINK=$VITE_STATUS_LINK" 
          - echo "VITE_COGNITO_REGION=$VITE_COGNITO_REGION"
          - echo "VITE_COGNITO_USER_POOL_ID=$VITE_COGNITO_USER_POOL_ID"
          - echo "VITE_COGNITO_USER_POOL_WEB_CLIENT_ID=$VITE_COGNITO_USER_POOL_WEB_CLIENT_ID" 
          - echo "VITE_FUSION_CHART_LICENSE_KEY=$VITE_FUSION_CHART_LICENSE_KEY" 
          - echo "VITE_PUBLIC_API_URL=$VITE_PUBLIC_API_URL"
          - echo "VITE_PORTAL_URL=$VITE_PORTAL_URL" 
          - echo "VITE_RECAPTCHA_SITE_KEY=$VITE_RECAPTCHA_SITE_KEY" 
          - echo "VITE_RECAPTCHA_KEY=$VITE_RECAPTCHA_KEY" 
          - pnpm exec nx run n360-portal:build:$DEPLOY_ENV --verbose

          - pipe: atlassian/aws-s3-deploy:0.4.4
            variables:
              AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
              AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
              AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION
              S3_BUCKET: $AWS_S3_Bucket
              LOCAL_PATH: 'dist/apps/n360-portal/'
          - pipe: atlassian/aws-cloudfront-invalidate:0.6.0
            variables:
              AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
              AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
              AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION
              DISTRIBUTION_ID: $CLOUDFRONT_DISTRIBUTION_ID
        artifacts:
          - dist/**
pipelines:
  pull-requests:
    '**':
      - step: *Build
  branches:
    'development':
      - step: *Build
      - step: 
          name: Build and deploy
          deployment: development
          <<: *Build-Deploy
    'staging':
      - step: *Build
      - step: 
          name: Build and deploy
          deployment: master
          <<: *Build-Deploy
    'production':
      - step: *Build
      - step: 
          name: Build and deploy
          deployment: production
          <<: *Build-Deploy

My team and I can't figure out how to solve this problem and there isn't much substance in the Nx documentation about this nor in threads that have the same problem as us.

Thanks in advance!

I tried getting everything back together in a single .env file which did not change anything I tried restructuring the vite.config.ts to only return the defineConfig object which didn't work

Upvotes: 2

Views: 543

Answers (1)

Yoh Suzuki
Yoh Suzuki

Reputation: 1465

We had a similar issue. This has to do with the order that .env files are loaded.

If you have both a .env and a .env.prod, Nx goes down the list and loads .env first, and then Vite no longer has an opportunity to overwrite with .env.prod. At least, this is our leading theory.

We fixed our issue by using the .env.build that Nx prefers over the .env.prod that Vite prefers.

Upvotes: 1

Related Questions