mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-26 23:52:06 +00:00
feat: runtime config and built-in dotenv support (#7312)
Co-authored-by: Sébastien Chopin <seb@nuxtjs.com> Co-authored-by: Alexander Lichter <manniL@gmx.net>
This commit is contained in:
parent
0c81c52c41
commit
0337932115
@ -16,6 +16,7 @@ module.exports = {
|
|||||||
rules: {
|
rules: {
|
||||||
'no-console': 'error',
|
'no-console': 'error',
|
||||||
'no-debugger': 'error',
|
'no-debugger': 'error',
|
||||||
|
'no-template-curly-in-string': 0,
|
||||||
quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }]
|
quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }]
|
||||||
},
|
},
|
||||||
overrides: [{
|
overrides: [{
|
||||||
|
@ -770,6 +770,11 @@ export default class Builder {
|
|||||||
if (this.ignore.ignoreFile) {
|
if (this.ignore.ignoreFile) {
|
||||||
nuxtRestartWatch.push(this.ignore.ignoreFile)
|
nuxtRestartWatch.push(this.ignore.ignoreFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.options._envConfig && this.options._envConfig.dotenv) {
|
||||||
|
nuxtRestartWatch.push(this.options._envConfig.dotenv)
|
||||||
|
}
|
||||||
|
|
||||||
// If default page displayed, watch for first page creation
|
// If default page displayed, watch for first page creation
|
||||||
if (this._nuxtPages && this._defaultPage) {
|
if (this._nuxtPages && this._defaultPage) {
|
||||||
nuxtRestartWatch.push(path.join(this.options.srcDir, this.options.dir.pages))
|
nuxtRestartWatch.push(path.join(this.options.srcDir, this.options.dir.pages))
|
||||||
|
@ -54,5 +54,15 @@ export default {
|
|||||||
alias: 'h',
|
alias: 'h',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Display this message'
|
description: 'Display this message'
|
||||||
|
},
|
||||||
|
processenv: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: true,
|
||||||
|
description: 'Disable reading from `process.env` and updating it with dotenv'
|
||||||
|
},
|
||||||
|
dotenv: {
|
||||||
|
type: 'string',
|
||||||
|
default: '.env',
|
||||||
|
description: 'Specify path to dotenv file (default: `.env`). Use `false` to disable'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,11 @@ export async function loadNuxtConfig (argv, configContext) {
|
|||||||
const options = await _loadNuxtConfig({
|
const options = await _loadNuxtConfig({
|
||||||
rootDir,
|
rootDir,
|
||||||
configFile,
|
configFile,
|
||||||
configContext
|
configContext,
|
||||||
|
envConfig: {
|
||||||
|
dotenv: argv.dotenv === 'false' ? false : argv.dotenv,
|
||||||
|
env: argv.processenv ? process.env : {}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Nuxt Mode
|
// Nuxt Mode
|
||||||
|
@ -27,6 +27,12 @@ exports[`cli/command builds help text 1`] = `
|
|||||||
--version, -v Display the Nuxt
|
--version, -v Display the Nuxt
|
||||||
version
|
version
|
||||||
--help, -h Display this message
|
--help, -h Display this message
|
||||||
|
--no-processenv Disable reading from
|
||||||
|
process.env and updating it with
|
||||||
|
dotenv
|
||||||
|
--dotenv Specify path to
|
||||||
|
dotenv file (default: .env). Use
|
||||||
|
false to disable
|
||||||
--port, -p Port number on which
|
--port, -p Port number on which
|
||||||
to start the application
|
to start the application
|
||||||
--hostname, -H Hostname on which to
|
--hostname, -H Hostname on which to
|
||||||
|
@ -21,8 +21,8 @@ describe('cli/command', () => {
|
|||||||
const cmd = new Command({ options: allOptions })
|
const cmd = new Command({ options: allOptions })
|
||||||
const minimistOptions = cmd._getMinimistOptions()
|
const minimistOptions = cmd._getMinimistOptions()
|
||||||
|
|
||||||
expect(minimistOptions.string.length).toBe(6)
|
expect(minimistOptions.string.length).toBe(7)
|
||||||
expect(minimistOptions.boolean.length).toBe(5)
|
expect(minimistOptions.boolean.length).toBe(6)
|
||||||
expect(minimistOptions.alias.c).toBe('config-file')
|
expect(minimistOptions.alias.c).toBe('config-file')
|
||||||
expect(minimistOptions.default.c).toBe(common['config-file'].default)
|
expect(minimistOptions.default.c).toBe(common['config-file'].default)
|
||||||
})
|
})
|
||||||
@ -71,7 +71,13 @@ describe('cli/command', () => {
|
|||||||
expect(options.server.port).toBe(3001)
|
expect(options.server.port).toBe(3001)
|
||||||
expect(consola.fatal).toHaveBeenCalledWith('Provided hostname argument has no value') // hostname check
|
expect(consola.fatal).toHaveBeenCalledWith('Provided hostname argument has no value') // hostname check
|
||||||
expect(loadConfigSpy).toHaveBeenCalledTimes(1)
|
expect(loadConfigSpy).toHaveBeenCalledTimes(1)
|
||||||
expect(loadConfigSpy).toHaveBeenCalledWith(expect.any(Object), { command: 'test', dev: false })
|
expect(loadConfigSpy).toHaveBeenCalledWith(expect.any(Object), {
|
||||||
|
command: 'test',
|
||||||
|
dev: false,
|
||||||
|
env: expect.objectContaining({
|
||||||
|
NODE_ENV: 'test'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
loadConfigSpy.mockRestore()
|
loadConfigSpy.mockRestore()
|
||||||
})
|
})
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"@nuxt/utils": "2.12.1",
|
"@nuxt/utils": "2.12.1",
|
||||||
"consola": "^2.12.1",
|
"consola": "^2.12.1",
|
||||||
"defu": "^2.0.2",
|
"defu": "^2.0.2",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
"esm": "^3.2.25",
|
"esm": "^3.2.25",
|
||||||
"std-env": "^2.2.1"
|
"std-env": "^2.2.1"
|
||||||
},
|
},
|
||||||
|
@ -77,5 +77,9 @@ export default () => ({
|
|||||||
editor: undefined,
|
editor: undefined,
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
hooks: null
|
hooks: null,
|
||||||
|
|
||||||
|
// runtimeConfig
|
||||||
|
privateRuntimeConfig: {},
|
||||||
|
publicRuntimeConfig: {}
|
||||||
})
|
})
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import fs from 'fs'
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
import dotenv from 'dotenv'
|
||||||
import { clearRequireCache, scanRequireTree } from '@nuxt/utils'
|
import { clearRequireCache, scanRequireTree } from '@nuxt/utils'
|
||||||
import esm from 'esm'
|
import esm from 'esm'
|
||||||
import { defaultNuxtConfigFile } from './config'
|
import { defaultNuxtConfigFile } from './config'
|
||||||
|
|
||||||
export async function loadNuxtConfig ({
|
export async function loadNuxtConfig ({
|
||||||
rootDir = '.',
|
rootDir = '.',
|
||||||
|
envConfig = {},
|
||||||
configFile = defaultNuxtConfigFile,
|
configFile = defaultNuxtConfigFile,
|
||||||
configContext = {},
|
configContext = {},
|
||||||
configOverrides = {}
|
configOverrides = {}
|
||||||
@ -27,6 +30,23 @@ export async function loadNuxtConfig ({
|
|||||||
configFile = undefined
|
configFile = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load env
|
||||||
|
envConfig = {
|
||||||
|
dotenv: '.env',
|
||||||
|
env: process.env,
|
||||||
|
expand: true,
|
||||||
|
...envConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
const env = loadEnv(envConfig, rootDir)
|
||||||
|
|
||||||
|
// Fill process.env so it is accessible in nuxt.config
|
||||||
|
for (const key in env) {
|
||||||
|
if (!key.startsWith('_') && envConfig.env[key] === undefined) {
|
||||||
|
envConfig.env[key] = env[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (configFile) {
|
if (configFile) {
|
||||||
// Clear cache
|
// Clear cache
|
||||||
clearRequireCache(configFile)
|
clearRequireCache(configFile)
|
||||||
@ -66,5 +86,85 @@ export async function loadNuxtConfig ({
|
|||||||
options.rootDir = rootDir
|
options.rootDir = rootDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load env to options._env
|
||||||
|
options._env = env
|
||||||
|
options._envConfig = envConfig
|
||||||
|
if (configContext) { configContext.env = env }
|
||||||
|
|
||||||
|
// Expand and interpolate runtimeConfig from _env
|
||||||
|
if (envConfig.expand) {
|
||||||
|
for (const c of ['publicRuntimeConfig', 'privateRuntimeConfig']) {
|
||||||
|
if (options[c]) {
|
||||||
|
if (typeof options[c] === 'function') {
|
||||||
|
options[c] = options[c](env)
|
||||||
|
}
|
||||||
|
expand(options[c], env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadEnv (envConfig, rootDir = process.cwd()) {
|
||||||
|
const env = Object.create(null)
|
||||||
|
|
||||||
|
// Read dotenv
|
||||||
|
if (envConfig.dotenv) {
|
||||||
|
envConfig.dotenv = path.resolve(rootDir, envConfig.dotenv)
|
||||||
|
if (fs.existsSync(envConfig.dotenv)) {
|
||||||
|
const parsed = dotenv.parse(fs.readFileSync(envConfig.dotenv, 'utf-8'))
|
||||||
|
Object.assign(env, parsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply process.env
|
||||||
|
if (!envConfig.env._applied) {
|
||||||
|
Object.assign(env, envConfig.env)
|
||||||
|
envConfig.env._applied = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate env
|
||||||
|
if (envConfig.expand) {
|
||||||
|
expand(env)
|
||||||
|
}
|
||||||
|
|
||||||
|
return env
|
||||||
|
}
|
||||||
|
|
||||||
|
// Based on https://github.com/motdotla/dotenv-expand
|
||||||
|
function expand (target, source = {}) {
|
||||||
|
function getValue (key) {
|
||||||
|
// Source value 'wins' over target value
|
||||||
|
return source[key] !== undefined ? source[key] : (target[key] || '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function interpolate (value) {
|
||||||
|
const matches = value.match(/(.?\${?(?:[a-zA-Z0-9_:]+)?}?)/g) || []
|
||||||
|
return matches.reduce((newValue, match) => {
|
||||||
|
const parts = /(.?)\${?([a-zA-Z0-9_:]+)?}?/g.exec(match)
|
||||||
|
const prefix = parts[1]
|
||||||
|
|
||||||
|
let value, replacePart
|
||||||
|
|
||||||
|
if (prefix === '\\') {
|
||||||
|
replacePart = parts[0]
|
||||||
|
value = replacePart.replace('\\$', '$')
|
||||||
|
} else {
|
||||||
|
const key = parts[2]
|
||||||
|
replacePart = parts[0].substring(prefix.length)
|
||||||
|
|
||||||
|
value = getValue(key)
|
||||||
|
|
||||||
|
// Resolve recursive interpolations
|
||||||
|
value = interpolate(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newValue.replace(replacePart, value)
|
||||||
|
}, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in target) {
|
||||||
|
target[key] = interpolate(getValue(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -294,6 +294,8 @@ Object {
|
|||||||
"name": "page",
|
"name": "page",
|
||||||
},
|
},
|
||||||
"plugins": Array [],
|
"plugins": Array [],
|
||||||
|
"privateRuntimeConfig": Object {},
|
||||||
|
"publicRuntimeConfig": Object {},
|
||||||
"render": Object {
|
"render": Object {
|
||||||
"bundleRenderer": Object {
|
"bundleRenderer": Object {
|
||||||
"runInNewContext": false,
|
"runInNewContext": false,
|
||||||
|
@ -266,6 +266,8 @@ Object {
|
|||||||
"name": "page",
|
"name": "page",
|
||||||
},
|
},
|
||||||
"plugins": Array [],
|
"plugins": Array [],
|
||||||
|
"privateRuntimeConfig": Object {},
|
||||||
|
"publicRuntimeConfig": Object {},
|
||||||
"render": Object {
|
"render": Object {
|
||||||
"bundleRenderer": Object {
|
"bundleRenderer": Object {
|
||||||
"runInNewContext": undefined,
|
"runInNewContext": undefined,
|
||||||
@ -632,6 +634,8 @@ Object {
|
|||||||
"name": "page",
|
"name": "page",
|
||||||
},
|
},
|
||||||
"plugins": Array [],
|
"plugins": Array [],
|
||||||
|
"privateRuntimeConfig": Object {},
|
||||||
|
"publicRuntimeConfig": Object {},
|
||||||
"render": Object {
|
"render": Object {
|
||||||
"bundleRenderer": Object {
|
"bundleRenderer": Object {
|
||||||
"runInNewContext": undefined,
|
"runInNewContext": undefined,
|
||||||
|
@ -98,7 +98,7 @@ Vue.config.$nuxt.<%= globals.nuxt %> = true
|
|||||||
const errorHandler = Vue.config.errorHandler || console.error
|
const errorHandler = Vue.config.errorHandler || console.error
|
||||||
|
|
||||||
// Create and mount App
|
// Create and mount App
|
||||||
createApp().then(mountApp).catch(errorHandler)
|
createApp(null, NUXT.config).then(mountApp).catch(errorHandler)
|
||||||
|
|
||||||
<% if (features.transitions) { %>
|
<% if (features.transitions) { %>
|
||||||
function componentOption (component, key, ...args) {
|
function componentOption (component, key, ...args) {
|
||||||
|
@ -66,7 +66,7 @@ const defaultTransition = <%=
|
|||||||
%><%= isTest ? '// eslint-disable-line' : '' %>
|
%><%= isTest ? '// eslint-disable-line' : '' %>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
async function createApp (ssrContext) {
|
async function createApp(ssrContext, config = {}) {
|
||||||
const router = await createRouter(ssrContext)
|
const router = await createRouter(ssrContext)
|
||||||
|
|
||||||
<% if (store) { %>
|
<% if (store) { %>
|
||||||
@ -162,8 +162,7 @@ async function createApp (ssrContext) {
|
|||||||
ssrContext
|
ssrContext
|
||||||
})
|
})
|
||||||
|
|
||||||
<% if (plugins.length) { %>
|
function inject(key, value) {
|
||||||
const inject = function (key, value) {
|
|
||||||
if (!key) {
|
if (!key) {
|
||||||
throw new Error('inject(key, value) has no key provided')
|
throw new Error('inject(key, value) has no key provided')
|
||||||
}
|
}
|
||||||
@ -199,7 +198,9 @@ async function createApp (ssrContext) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
<% } %>
|
|
||||||
|
// Inject runtime config as $config
|
||||||
|
inject('config', config)
|
||||||
|
|
||||||
<% if (store) { %>
|
<% if (store) { %>
|
||||||
if (process.client) {
|
if (process.client) {
|
||||||
|
@ -77,9 +77,10 @@ export default async (ssrContext) => {
|
|||||||
if (process.static && ssrContext.url) {
|
if (process.static && ssrContext.url) {
|
||||||
ssrContext.url = ssrContext.url.split('?')[0]
|
ssrContext.url = ssrContext.url.split('?')[0]
|
||||||
}
|
}
|
||||||
|
// Public runtime config
|
||||||
|
ssrContext.nuxt.config = ssrContext.runtimeConfig.public
|
||||||
// Create the app definition and the instance (created for each request)
|
// Create the app definition and the instance (created for each request)
|
||||||
const { app, router<%= (store ? ', store' : '') %> } = await createApp(ssrContext)
|
const { app, router<%= (store ? ', store' : '') %> } = await createApp(ssrContext, { ...ssrContext.runtimeConfig.public, ...ssrContext.runtimeConfig.private })
|
||||||
const _app = new Vue(app)
|
const _app = new Vue(app)
|
||||||
// Add ssr route path to nuxt context so we can account for page navigation between ssr and csr
|
// Add ssr route path to nuxt context so we can account for page navigation between ssr and csr
|
||||||
ssrContext.nuxt.routePath = app.context.route.path
|
ssrContext.nuxt.routePath = app.context.route.path
|
||||||
|
@ -291,6 +291,12 @@ export default class VueRenderer {
|
|||||||
renderContext.modern = modernMode === 'client' || isModernRequest(req, modernMode)
|
renderContext.modern = modernMode === 'client' || isModernRequest(req, modernMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set runtime config on renderContext
|
||||||
|
renderContext.runtimeConfig = {
|
||||||
|
private: renderContext.spa ? {} : { ...this.options.privateRuntimeConfig },
|
||||||
|
public: { ...this.options.publicRuntimeConfig }
|
||||||
|
}
|
||||||
|
|
||||||
// Call renderContext hook
|
// Call renderContext hook
|
||||||
await this.serverContext.nuxt.callHook('vue-renderer:context', renderContext)
|
await this.serverContext.nuxt.callHook('vue-renderer:context', renderContext)
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import cloneDeep from 'lodash/cloneDeep'
|
|||||||
import VueMeta from 'vue-meta'
|
import VueMeta from 'vue-meta'
|
||||||
import { createRenderer } from 'vue-server-renderer'
|
import { createRenderer } from 'vue-server-renderer'
|
||||||
import LRU from 'lru-cache'
|
import LRU from 'lru-cache'
|
||||||
|
import devalue from '@nuxt/devalue'
|
||||||
import { TARGETS, isModernRequest } from '@nuxt/utils'
|
import { TARGETS, isModernRequest } from '@nuxt/utils'
|
||||||
import BaseRenderer from './base'
|
import BaseRenderer from './base'
|
||||||
|
|
||||||
@ -148,12 +149,16 @@ export default class SPARenderer extends BaseRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serialize state (runtime config)
|
||||||
let APP = `${meta.BODY_SCRIPTS_PREPEND}<div id="${this.serverContext.globals.id}">${this.serverContext.resources.loadingHTML}</div>${meta.BODY_SCRIPTS}`
|
let APP = `${meta.BODY_SCRIPTS_PREPEND}<div id="${this.serverContext.globals.id}">${this.serverContext.resources.loadingHTML}</div>${meta.BODY_SCRIPTS}`
|
||||||
|
|
||||||
if (renderContext.staticAssetsBase) {
|
if (renderContext.staticAssetsBase) {
|
||||||
// Full static, add window.__NUXT_STATIC__
|
APP += `<script>window.__NUXT_STATIC__='${renderContext.staticAssetsBase}'</script>`
|
||||||
APP += `<script>window.__NUXT_STATIC__='${renderContext.staticAssetsBase}';window.${this.serverContext.globals.context}={spa:!0}</script>`
|
|
||||||
}
|
}
|
||||||
|
APP += `<script>window.${this.serverContext.globals.context}=${devalue({
|
||||||
|
config: renderContext.runtimeConfig.public,
|
||||||
|
spa: true
|
||||||
|
})}</script>`
|
||||||
|
|
||||||
// Prepare template params
|
// Prepare template params
|
||||||
const templateParams = {
|
const templateParams = {
|
||||||
|
45
test/dev/runtime-config.test.js
Normal file
45
test/dev/runtime-config.test.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { loadFixture, getPort, Nuxt } from '../utils'
|
||||||
|
|
||||||
|
let port
|
||||||
|
const url = route => 'http://localhost:' + port + route
|
||||||
|
|
||||||
|
let nuxt = null
|
||||||
|
|
||||||
|
describe('basic ssr', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
const options = await loadFixture('runtime-config')
|
||||||
|
nuxt = new Nuxt(options)
|
||||||
|
await nuxt.ready()
|
||||||
|
|
||||||
|
port = await getPort()
|
||||||
|
await nuxt.server.listen(port, '0.0.0.0')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('SSR payload', async () => {
|
||||||
|
const window = await nuxt.server.renderAndGetWindow(url('/'))
|
||||||
|
const payload = window.__NUXT__
|
||||||
|
|
||||||
|
expect(payload.config).toMatchObject({
|
||||||
|
baseURL: '/api'
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(payload.data[0].serverConfig).toMatchObject({
|
||||||
|
baseURL: 'https://google.com/api',
|
||||||
|
API_SECRET: '1234'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test('SPA payload ', async () => {
|
||||||
|
const window = await nuxt.server.renderAndGetWindow(url('/?spa'))
|
||||||
|
const payload = window.__NUXT__
|
||||||
|
|
||||||
|
expect(payload.config).toMatchObject({
|
||||||
|
baseURL: '/api'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Close server and ask nuxt to stop listening to file changes
|
||||||
|
afterAll(async () => {
|
||||||
|
await nuxt.close()
|
||||||
|
})
|
||||||
|
})
|
@ -20,7 +20,7 @@ describe('nuxt minimal vue-app bundle size limit', () => {
|
|||||||
it('should stay within the size limit range', async () => {
|
it('should stay within the size limit range', async () => {
|
||||||
const filter = filename => filename === 'vue-app.nuxt.js'
|
const filter = filename => filename === 'vue-app.nuxt.js'
|
||||||
const legacyResourcesSize = await getResourcesSize(distDir, 'client', { filter })
|
const legacyResourcesSize = await getResourcesSize(distDir, 'client', { filter })
|
||||||
const LEGACY_JS_RESOURCES_KB_SIZE = 16.2
|
const LEGACY_JS_RESOURCES_KB_SIZE = 16.5
|
||||||
expect(legacyResourcesSize.uncompressed).toBeWithinSize(LEGACY_JS_RESOURCES_KB_SIZE)
|
expect(legacyResourcesSize.uncompressed).toBeWithinSize(LEGACY_JS_RESOURCES_KB_SIZE)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
4
test/fixtures/runtime-config/.env
vendored
Normal file
4
test/fixtures/runtime-config/.env
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
BASE_URL=/api
|
||||||
|
PUBLIC_URL=https://google.com
|
||||||
|
SERVER_BASE_URL
|
||||||
|
API_SECRET=1234
|
17
test/fixtures/runtime-config/nuxt.config.js
vendored
Normal file
17
test/fixtures/runtime-config/nuxt.config.js
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export default {
|
||||||
|
publicRuntimeConfig: {
|
||||||
|
baseURL: process.env.BASE_URL
|
||||||
|
},
|
||||||
|
privateRuntimeConfig: {
|
||||||
|
baseURL: '${PUBLIC_URL}${BASE_URL}',
|
||||||
|
API_SECRET: ''
|
||||||
|
},
|
||||||
|
serverMiddleware: [
|
||||||
|
(req, _, next) => {
|
||||||
|
if (req.url.includes('?spa')) {
|
||||||
|
req.spa = true
|
||||||
|
}
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
30
test/fixtures/runtime-config/pages/index.vue
vendored
Normal file
30
test/fixtures/runtime-config/pages/index.vue
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<template>
|
||||||
|
<pre v-text="JSON.stringify(config, null, 2)" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
asyncData ({ $config }) {
|
||||||
|
return {
|
||||||
|
serverConfig: $config
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
clientConfig: { please: 'wait' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
config () {
|
||||||
|
return {
|
||||||
|
client: this.clientConfig,
|
||||||
|
server: this.serverConfig,
|
||||||
|
$config: this.$config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.clientConfig = this.$config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
3
test/fixtures/runtime-config/runtime-config.test.js
vendored
Normal file
3
test/fixtures/runtime-config/runtime-config.test.js
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { buildFixture } from '../../utils/build'
|
||||||
|
|
||||||
|
buildFixture('runtime-config')
|
@ -2,6 +2,7 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { defaultsDeep } from 'lodash'
|
import { defaultsDeep } from 'lodash'
|
||||||
import { version as coreVersion } from '../../packages/core/package.json'
|
import { version as coreVersion } from '../../packages/core/package.json'
|
||||||
|
import { loadNuxtConfig } from '../../packages/config/src/index'
|
||||||
|
|
||||||
export { Nuxt } from '../../packages/core/src/index'
|
export { Nuxt } from '../../packages/core/src/index'
|
||||||
export { Builder } from '../../packages/builder/src/index'
|
export { Builder } from '../../packages/builder/src/index'
|
||||||
@ -13,25 +14,13 @@ export const version = `v${coreVersion}`
|
|||||||
|
|
||||||
export const loadFixture = async function (fixture, overrides) {
|
export const loadFixture = async function (fixture, overrides) {
|
||||||
const rootDir = path.resolve(__dirname, '..', 'fixtures', fixture)
|
const rootDir = path.resolve(__dirname, '..', 'fixtures', fixture)
|
||||||
let config = {}
|
const config = await loadNuxtConfig({
|
||||||
|
rootDir,
|
||||||
try {
|
configOverrides: {
|
||||||
config = await import(`../fixtures/${fixture}/nuxt.config`)
|
dev: false,
|
||||||
config = config.default || config
|
test: true
|
||||||
} catch (e) {
|
|
||||||
// Ignore MODULE_NOT_FOUND
|
|
||||||
if (e.code !== 'MODULE_NOT_FOUND') {
|
|
||||||
throw e
|
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
if (typeof config === 'function') {
|
|
||||||
config = await config()
|
|
||||||
}
|
|
||||||
|
|
||||||
config.rootDir = rootDir
|
|
||||||
config.dev = false
|
|
||||||
config.test = true
|
|
||||||
|
|
||||||
// disable terser to speed-up fixture builds
|
// disable terser to speed-up fixture builds
|
||||||
if (config.build) {
|
if (config.build) {
|
||||||
|
15
yarn.lock
15
yarn.lock
@ -252,16 +252,16 @@
|
|||||||
chalk "^2.0.0"
|
chalk "^2.0.0"
|
||||||
js-tokens "^4.0.0"
|
js-tokens "^4.0.0"
|
||||||
|
|
||||||
|
"@babel/parser@7.7.5", "@babel/parser@^7.7.0":
|
||||||
|
version "7.7.5"
|
||||||
|
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz#cbf45321619ac12d83363fcf9c94bb67fa646d71"
|
||||||
|
integrity sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==
|
||||||
|
|
||||||
"@babel/parser@^7.1.0", "@babel/parser@^7.8.6", "@babel/parser@^7.9.6":
|
"@babel/parser@^7.1.0", "@babel/parser@^7.8.6", "@babel/parser@^7.9.6":
|
||||||
version "7.9.6"
|
version "7.9.6"
|
||||||
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz#3b1bbb30dabe600cd72db58720998376ff653bc7"
|
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz#3b1bbb30dabe600cd72db58720998376ff653bc7"
|
||||||
integrity sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==
|
integrity sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==
|
||||||
|
|
||||||
"@babel/parser@^7.7.0":
|
|
||||||
version "7.7.5"
|
|
||||||
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz#cbf45321619ac12d83363fcf9c94bb67fa646d71"
|
|
||||||
integrity sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==
|
|
||||||
|
|
||||||
"@babel/plugin-proposal-async-generator-functions@^7.8.3":
|
"@babel/plugin-proposal-async-generator-functions@^7.8.3":
|
||||||
version "7.8.3"
|
version "7.8.3"
|
||||||
resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f"
|
resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f"
|
||||||
@ -4951,6 +4951,11 @@ dot-prop@^5.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-obj "^2.0.0"
|
is-obj "^2.0.0"
|
||||||
|
|
||||||
|
dotenv@^8.2.0:
|
||||||
|
version "8.2.0"
|
||||||
|
resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
|
||||||
|
integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
|
||||||
|
|
||||||
duplexer@^0.1.1:
|
duplexer@^0.1.1:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
|
resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
|
||||||
|
Loading…
Reference in New Issue
Block a user