3

I have a custom .js file that I place inside the public folder in my NextJS app. I need to be able to use environment variables in that .js file, but environment variables don't seem to be available there.

I read that files in the public folder don't go through the webpack build process.

How do I customize my Next.js app so it builds an additional file inside the public folder? I found a suggestion (option 1 in the answer) on how to do it in a Vue.js app. Anyone know how to achieve something similar in Next.js?

artooras
  • 6,315
  • 9
  • 45
  • 78
  • 1
    Out of curiosity, what's the reason for having the env vars file in the `public` folder? – juliomalves Sep 20 '21 at 12:56
  • 1
    My script's functionality relies on the base path of the project. Currently I have two separate .js files in the public folder with identical code, but different base paths (localhost for dev, public url for production). I'd like to maintain just one file which compiles at build time accordingly. – artooras Sep 20 '21 at 13:22
  • 1
    Actually, I have just clarified the title of the question - it may have been a bit misleading... :) – artooras Sep 20 '21 at 13:45
  • @juliomalves I want to have a service worker .js file served from the public/ folder, and inside the serviceWorker must access variables from .env – Dynalon May 10 '23 at 07:02
  • Try updating the js file with the values you need when deploying your app. This can easily be done with for example an PowerShell task – Remko May 10 '23 at 19:49

1 Answers1

1

ok so first, you'll need to install a package called copy-webpack-plugin:

npm install copy-webpack-plugin --save-dev

This package should allow you to customise the build process.

Next, in your next.config.js file, you can add a custom Webpack configuration that writes your environment variables into a new .js file and then copies it to your public folder during the build process:

const CopyPlugin = require('copy-webpack-plugin');
const path = require('path');
const fs = require('fs');

module.exports = {
  webpack: (config, { dev, isServer }) => {
    if (!dev && !isServer) {
      // The .js file you want to create
      const fileContent = `const env = ${JSON.stringify(process.env)};`;

      // The path of the file
      const filePath = path.join(__dirname, 'public', 'env.js');

      // Create the file
      fs.writeFileSync(filePath, fileContent, 'utf8');

      // Configure webpack to copy the file to the public folder
      config.plugins.push(
        new CopyPlugin({
          patterns: [
            { from: 'public', to: '' },
          ],
        })
      );
    }

    return config;
  },
};

One important thing to note here: by doing this, you're exposing all your environment variables to the client-side. Which is a bit risky if you've got any sensitive data in them. You'll probably want to adjust the fileContent variable to only include the variables you need:

const fileContent = `const env = {MY_VAR: "${process.env.MY_VAR}"};`;

just so you're only exposing the variables you need in your public folder. Replace "MY_VAR" with the name of your environment variable.

Hopefully some of this helps

luke
  • 207
  • 3
  • This is was almost perfectly what I need; since you cannot import/require files inside a serviceworker, I read in the serviceworker content using `fs.readFileSync` and write the env content plus the service worker content using `fs.appendFileSync()` and copy that output over. Inside the server worker I can then access the env variable (and yes, only expose env vars you really want to expose, not private ones). – Dynalon May 12 '23 at 15:04