diff --git a/errors/serverless-publicRuntimeConfig.md b/errors/serverless-publicRuntimeConfig.md new file mode 100644 index 00000000..e6feecbe --- /dev/null +++ b/errors/serverless-publicRuntimeConfig.md @@ -0,0 +1,22 @@ +# Using `publicRuntimeConfig` with `target` set to `serverless` + +#### Why This Error Occurred + +In the `serverless` target environment `next.config.js` is not loaded, so we don't support `publicRuntimeConfig`. +#### Possible Ways to Fix It + +Use config option `env` to set **build time** variables like such: + +```js +// next.config.js +module.exports = { + env: { + special: "value" + } +} +``` + +```js +// pages/index.js +console.log(process.env.special) // value +``` \ No newline at end of file diff --git a/packages/next/README.md b/packages/next/README.md index 173e3f32..91523dea 100644 --- a/packages/next/README.md +++ b/packages/next/README.md @@ -1551,7 +1551,49 @@ The `modules` option on `"preset-env"` should be kept to `false` otherwise webpa ### Exposing configuration to the server / client side -The `next/config` module gives your app access to runtime configuration stored in your `next.config.js`. Place any server-only runtime config under a `serverRuntimeConfig` property and anything accessible to both client and server-side code under `publicRuntimeConfig`. +There is a common need in applications to provide configuration values. + +Next.js supports 2 ways of providing configuration: + +- Build-time configuration +- Runtime configuration + +#### Build time configuration + +The way build-time configuration works is by inlining the provided values into the Javascript bundle. + +You can add the `env` key in `next.config.js`: + +```js +// next.config.js +module.exports = { + env: { + customKey: 'value' + } +} +``` + +This will allow you to use `process.env.customKey` in your code. For example: + +```jsx +// pages/index.js +export default function Index() { + return

The value of customEnv is: {process.env.customEnv}

+} +``` + +#### Runtime configuration + +> :warning: Note that this option is not available when using `target: 'serverless'` + +> :warning: Generally you want to use build-time configuration to provide your configuration. +The reason for this is that runtime configuration adds a small rendering / initialization overhead. + +The `next/config` module gives your app access to the `publicRuntimeConfig` and `serverRuntimeConfig` stored in your `next.config.js`. + +Place any server-only runtime config under a `serverRuntimeConfig` property. + +Anything accessible to both client and server-side code should be under `publicRuntimeConfig`. ```js // next.config.js diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 136dac85..0738bdbc 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -48,6 +48,8 @@ export default async function build (dir: string, conf = null): Promise { let result: CompilerResult = {warnings: [], errors: []} if (config.target === 'serverless') { + if (config.publicRuntimeConfig) throw new Error('Cannot use publicRuntimeConfig with target=serverless https://err.sh/zeit/next.js/serverless-publicRuntimeConfig') + const clientResult = await runCompiler([configs[0]]) // Fail build if clientResult contains errors if(clientResult.errors.length > 0) { diff --git a/packages/next/build/webpack-config.js b/packages/next/build/webpack-config.js index 7fe18c9b..f801a5f6 100644 --- a/packages/next/build/webpack-config.js +++ b/packages/next/build/webpack-config.js @@ -291,10 +291,18 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer dev && new CaseSensitivePathPlugin(), // Since on macOS the filesystem is case-insensitive this will make sure your path are case-sensitive !dev && new webpack.HashedModuleIdsPlugin(), // Removes server/client code by minifier - new webpack.DefinePlugin({ - 'process.crossOrigin': JSON.stringify(config.crossOrigin), - 'process.browser': JSON.stringify(!isServer) - }), + new webpack.DefinePlugin(Object.assign( + {}, + config.env ? Object.keys(config.env) + .reduce((acc, key) => ({ + ...acc, + ...{ [`process.env.${key}`]: JSON.stringify(config.env[key]) } + }), {}) : {}, + { + 'process.crossOrigin': JSON.stringify(config.crossOrigin), + 'process.browser': JSON.stringify(!isServer) + } + )), // This is used in client/dev-error-overlay/hot-dev-client.js to replace the dist directory !isServer && dev && new webpack.DefinePlugin({ 'process.env.__NEXT_DIST_DIR': JSON.stringify(distDir) diff --git a/test/integration/config/next.config.js b/test/integration/config/next.config.js index 01f0a6c6..b0a83cc1 100644 --- a/test/integration/config/next.config.js +++ b/test/integration/config/next.config.js @@ -15,6 +15,9 @@ module.exports = withCSS(withSass({ publicRuntimeConfig: { staticFolder: '/static' }, + env: { + customVar: 'hello' + }, webpack (config, {buildId}) { // When next-css is `npm link`ed we have to solve loaders from the project root const nextLocation = path.join(require.resolve('next/package.json'), '../') diff --git a/test/integration/config/pages/next-config.js b/test/integration/config/pages/next-config.js index 0c00bbe3..204da150 100644 --- a/test/integration/config/pages/next-config.js +++ b/test/integration/config/pages/next-config.js @@ -4,4 +4,5 @@ const {serverRuntimeConfig, publicRuntimeConfig} = getConfig() export default () =>

{serverRuntimeConfig.mySecret}

{publicRuntimeConfig.staticFolder}

+

{process.env.customVar}

diff --git a/test/integration/config/test/client.js b/test/integration/config/test/client.js index 93b72548..2f571149 100644 --- a/test/integration/config/test/client.js +++ b/test/integration/config/test/client.js @@ -14,9 +14,11 @@ export default (context, render) => { const serverText = await browser.elementByCss('#server-only').text() const serverClientText = await browser.elementByCss('#server-and-client').text() + const envValue = await browser.elementByCss('#env').text() expect(serverText).toBe('') expect(serverClientText).toBe('/static') + expect(envValue).toBe('hello') browser.close() })