mirror of https://github.com/rancher/dashboard.git
Removing nuxt
This commit is contained in:
parent
7aade7ec4f
commit
bbb7eebc90
|
|
@ -12,6 +12,7 @@ dist-pkg
|
|||
.DS_Store
|
||||
shell/utils/dynamic-importer.js
|
||||
ksconfig.json
|
||||
nuxt
|
||||
storybook-static/
|
||||
utils/dynamic-importer.js
|
||||
shell/assets/fonts
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ echo Installing dependencies
|
|||
yarn install:ci
|
||||
|
||||
echo Building
|
||||
NUXT_ENV_commit=$GITHUB_SHA NUXT_ENV_version=$GITHUB_REF_NAME OUTPUT_DIR="$ARTIFACT_LOCATION" ROUTER_BASE="$ROUTER_BASE" RANCHER_ENV=$RANCHER_ENV API=$API RESOURCE_BASE=$RESOURCE_BASE EXCLUDES_PKG=$EXCLUDES_PKG yarn run build --spa
|
||||
COMMIT=$GITHUB_SHA VERSION=$GITHUB_REF_NAME OUTPUT_DIR="$ARTIFACT_LOCATION" ROUTER_BASE="$ROUTER_BASE" RANCHER_ENV=$RANCHER_ENV API=$API RESOURCE_BASE=$RESOURCE_BASE EXCLUDES_PKG=$EXCLUDES_PKG yarn run build --spa
|
||||
|
||||
echo Creating tar
|
||||
tar -czf $RELEASE_LOCATION.tar.gz -C $ARTIFACT_LOCATION .
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
module.exports = { env: { test: { presets: [['@babel/env', { targets: { node: 'current' } }]] } } };
|
||||
module.exports = require('./shell/babel.config.js');
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export default class CheckboxInputPo extends ComponentPo {
|
|||
return new CheckboxInputPo(
|
||||
self
|
||||
.find('.checkbox-outer-container')
|
||||
.contains(`${ label } `)
|
||||
.contains(label)
|
||||
.parent()
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ export default class LabeledInputPo extends ComponentPo {
|
|||
return new LabeledInputPo(
|
||||
self
|
||||
.find('.labeled-input', { includeShadowDom: true })
|
||||
.contains(`${ label } `)
|
||||
.contains(label)
|
||||
.next()
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
{
|
||||
"extends": "../tsconfig.default.json",
|
||||
"extends": "../shell/tsconfig.default.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"types": ["cypress"]
|
||||
"types": [
|
||||
"cypress"
|
||||
]
|
||||
},
|
||||
"include": ["./**/*.ts", "../types/*.ts"]
|
||||
"include": [
|
||||
"./**/*.ts",
|
||||
"../types/*.ts"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# Middleware
|
||||
|
||||
## Location
|
||||
The definitions of middleware reside in `shell/middleware`. Middleware added to the object in `shell/nuxt/middleware.js` will be initialized at the start of the app rendering.
|
||||
|
||||
|
||||
## Notes
|
||||
This file was generated by nuxt and will soon be redefined by hand. It's safe to add new middleware to this file.
|
||||
|
||||
## Pattern
|
||||
Define the middleware in a file that resides within `shell/middleware`. Then add the instantiation to the object that resides in `shell/nuxt/middleware.js`.
|
||||
|
||||
shell/middleware/i18n.js
|
||||
```js
|
||||
export default async function({
|
||||
isHMR, app, store, route, params, error, redirect
|
||||
}) {
|
||||
// If middleware is called from hot module replacement, ignore it
|
||||
if (isHMR) {
|
||||
return;
|
||||
}
|
||||
|
||||
await store.dispatch('i18n/init');
|
||||
}
|
||||
```
|
||||
|
||||
shell/nuxt/middleware.js
|
||||
```js
|
||||
...
|
||||
middleware['i18n'] = require('../middleware/i18n.js')
|
||||
middleware['i18n'] = middleware['i18n'].default || middleware['i18n']
|
||||
...
|
||||
```
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# Nuxt Plugins
|
||||
|
||||
## Location
|
||||
The definitions of plugins reside in `shell/plugins`. Plugins added to `shell/nuxt/index.js` will be initialized at the start of the app rendering.
|
||||
|
||||
|
||||
## Notes
|
||||
This file was generated by nuxt and will soon be redefined by hand. It's safe to add new plugins to this file.
|
||||
|
||||
## Pattern
|
||||
Define the store in a file that resides within `shell/plugins`. Then add the plugins import and execution to `shell/nuxt/index.js`.
|
||||
|
||||
shell/plugins/version.js
|
||||
```js
|
||||
/**
|
||||
* Fetch version metadata from backend /rancherversion API and store it
|
||||
*
|
||||
* This metadata does not change for an installation of Rancher
|
||||
*/
|
||||
|
||||
import { setVersionData } from '@shell/config/version';
|
||||
|
||||
export default async function({ store }) {
|
||||
try {
|
||||
const response = await store.dispatch('rancher/request', {
|
||||
url: '/rancherversion',
|
||||
method: 'get',
|
||||
redirectUnauthorized: false
|
||||
});
|
||||
|
||||
setVersionData(response);
|
||||
} catch (e) {
|
||||
console.warn('Failed to fetch Rancher version metadata', e); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
shell/nuxt/index.js
|
||||
```js
|
||||
...
|
||||
import version from '../plugins/version';
|
||||
...
|
||||
if (process.client && typeof version === 'function') {
|
||||
await version(app.context, inject);
|
||||
}
|
||||
...
|
||||
```
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# Routes
|
||||
|
||||
## Location
|
||||
|
||||
The core dashboard routes are defined in `shell/nuxt/router.js`.
|
||||
|
||||
|
||||
## Notes
|
||||
This file was generated by nuxt and will soon be redefined by hand. It's safe to add new routes to this file.
|
||||
|
||||
## Pattern
|
||||
First instantiate a page component at the top of the file. Then define a new route at the bottom of the file by giving the page component a unique path and name
|
||||
```js
|
||||
const about = () => interopDefault(import('../pages/about.vue'))
|
||||
...
|
||||
{
|
||||
path: "/about",
|
||||
component: about,
|
||||
name: "about"
|
||||
}
|
||||
...
|
||||
```
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Stores
|
||||
|
||||
## Location
|
||||
The definitions of stores reside in `shell/store`. Stores added to `shell/nuxt/store.js` will be initialized at the start of the app rendering.
|
||||
|
||||
|
||||
## Notes
|
||||
This file was generated by nuxt and will soon be redefined by hand. It's safe to add new stores to this file.
|
||||
|
||||
## Pattern
|
||||
Define the store in a file that resides within `shell/store`. Then add the store to `shell/nuxt/store.js`.
|
||||
|
||||
shell/nuxt/store.js
|
||||
```js
|
||||
...
|
||||
resolveStoreModules(require('../store/i18n.js'), 'i18n.js')
|
||||
...
|
||||
```
|
||||
|
|
@ -55,6 +55,10 @@ const sidebars = {
|
|||
'code-base-works/helm-chart-apps',
|
||||
'code-base-works/keyboard-shortcuts',
|
||||
'code-base-works/kubernetes-resources-data-load',
|
||||
'code-base-works/routes',
|
||||
'code-base-works/middleware',
|
||||
'code-base-works/stores',
|
||||
'code-base-works/nuxt-plugins',
|
||||
'code-base-works/machine-drivers',
|
||||
'code-base-works/performance',
|
||||
'code-base-works/sortable-table',
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"baseUrl": ".",
|
||||
"module": "commonjs",
|
||||
"paths": {
|
||||
"@/*": ["*"]
|
||||
},
|
||||
"sourceMap": true,
|
||||
"target": "es2017"
|
||||
},
|
||||
|
||||
"exclude": ["node_modules", "dist","tmp"]
|
||||
}
|
||||
28
package.json
28
package.json
|
|
@ -13,7 +13,7 @@
|
|||
"pkg/rancher-components"
|
||||
],
|
||||
"scripts": {
|
||||
"build-pkg": "./shell/scripts/build-pkg.sh",
|
||||
"build-pkg": "yarn lint && ./shell/scripts/build-pkg.sh",
|
||||
"publish-pkg": "./shell/scripts/publish-pkg.sh",
|
||||
"serve-pkgs": "./shell/scripts/serve-pkgs",
|
||||
"publish-shell": "./shell/scripts/publish-shell.sh",
|
||||
|
|
@ -24,20 +24,19 @@
|
|||
"test": "jest --watch",
|
||||
"test:ci": "jest --collectCoverage",
|
||||
"install:ci": "yarn install --frozen-lockfile",
|
||||
"nuxt": "./node_modules/.bin/nuxt",
|
||||
"dev": "source ./scripts/version && ./node_modules/.bin/nuxt dev",
|
||||
"mem-dev": "source ./scripts/version && node --max-old-space-size=8192 ./node_modules/.bin/nuxt dev",
|
||||
"dev": "source ./scripts/version && NODE_ENV=dev ./node_modules/.bin/vue-cli-service serve",
|
||||
"mem-dev": "source ./scripts/version && NODE_ENV=dev node --max-old-space-size=8192 ./node_modules/.bin/vue-cli-service serve",
|
||||
"docker-dev": "docker run --rm --name dashboard-dev -p 8005:8005 -e API=$API -v $(pwd):/src -v dashboard_node:/src/node_modules rancher/dashboard:dev",
|
||||
"docker:local:start": "docker run -d --restart=unless-stopped -p 80:80 -p 443:443 -e CATTLE_BOOTSTRAP_PASSWORD=password -e CATTLE_PASSWORD_MIN_LENGTH=3 --name cypress --privileged rancher/rancher:v2.7-head",
|
||||
"docker:local:stop": "docker kill cypress || docker rm cypress || true",
|
||||
"build": "./node_modules/.bin/nuxt build --devtools",
|
||||
"build": "yarn lint && ./node_modules/.bin/vue-cli-service build",
|
||||
"build:lib": "cd pkg/rancher-components && yarn build:lib",
|
||||
"analyze": "./node_modules/.bin/nuxt build --analyze",
|
||||
"start": "./node_modules/.bin/nuxt start",
|
||||
"analyze": "./node_modules/.bin/vue-cli-service build --report",
|
||||
"start": "./node_modules/.bin/vue-cli-service serve",
|
||||
"start:dev": "NODE_ENV=dev yarn start",
|
||||
"start:prod": "DEV_PORTS=true NODE_ENV=production yarn start",
|
||||
"generate": "./node_modules/.bin/nuxt generate",
|
||||
"dev-debug": "node --inspect ./node_modules/.bin/nuxt",
|
||||
"start:prod": "NODE_OPTIONS=--max_old_space_size=4096 DEV_PORTS=true NODE_ENV=production yarn start",
|
||||
"generate": "yarn build",
|
||||
"dev-debug": "node --inspect ./node_modules/.bin/vue-cli-service",
|
||||
"cy:e2e": "cypress open --e2e --browser chrome",
|
||||
"cy:open": "cypress open",
|
||||
"cy:run": "cypress run --browser chrome",
|
||||
|
|
@ -109,12 +108,18 @@
|
|||
"shell-quote": "1.7.3",
|
||||
"sinon": "8.1.1",
|
||||
"ts-node": "8.10.2",
|
||||
"ufo": "0.7.11",
|
||||
"unfetch": "4.2.0",
|
||||
"url-parse": "1.5.10",
|
||||
"v-tooltip": "2.0.3",
|
||||
"vue-client-only": "2.1.0",
|
||||
"vue-clipboard2": "0.3.1",
|
||||
"vue-codemirror": "4.0.6",
|
||||
"vue-js-modal": "1.3.35",
|
||||
"vue-meta": "2.4.0",
|
||||
"vue-no-ssr": "1.1.1",
|
||||
"vue-resize": "0.4.5",
|
||||
"vue-router": "3.6.5",
|
||||
"vue-select": "3.18.3",
|
||||
"vue-server-renderer": "2.6.14",
|
||||
"vue-shortkey": "3.1.7",
|
||||
|
|
@ -141,14 +146,13 @@
|
|||
"@nuxtjs/eslint-config-typescript": "6.0.1",
|
||||
"@nuxtjs/eslint-module": "1.2.0",
|
||||
"@nuxtjs/style-resources": "1.2.1",
|
||||
"@types/copy-webpack-plugin": "^5.0.3",
|
||||
"@types/jest": "27.4.1",
|
||||
"@types/lodash": "4.14.184",
|
||||
"@types/node": "16.4.3",
|
||||
"@types/vue-select": "3.16.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.33.0",
|
||||
"@typescript-eslint/parser": "4.33.0",
|
||||
"@vue/cli-plugin-babel": "4.5.15",
|
||||
"@vue/cli-plugin-typescript": "4.5.15",
|
||||
"@vue/cli-service": "4.5.15",
|
||||
"@vue/eslint-config-standard": "5.1.2",
|
||||
"@vue/test-utils": "1.2.1",
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@
|
|||
"registry": "http://localhost:4873"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "./node_modules/.bin/nuxt dev",
|
||||
"nuxt": "./node_modules/.bin/nuxt"
|
||||
"dev": "./node_modules/.bin/vue-cli-service dev"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ DIR=${GIT_TAG:-$COMMIT_BRANCH}
|
|||
OUTPUT_DIR=dist/${DIR}-embedded
|
||||
|
||||
echo "Building..."
|
||||
NUXT_ENV_commit=${COMMIT} NUXT_ENV_version=${VERSION} OUTPUT_DIR=$OUTPUT_DIR ROUTER_BASE='/dashboard' yarn run build
|
||||
COMMIT=${COMMIT} VERSION=${VERSION} OUTPUT_DIR=$OUTPUT_DIR ROUTER_BASE='/dashboard' yarn run build
|
||||
|
||||
if [ -v EMBED_PKG ]; then
|
||||
echo "Build and embed plugin from: $EMBED_PKG"
|
||||
|
|
|
|||
|
|
@ -25,4 +25,4 @@ BASE=${BASE:-https://releases.rancher.com/dashboard/${DIR}}
|
|||
|
||||
echo "Building for ${BASE}..."
|
||||
|
||||
NUXT_ENV_commit=${COMMIT} NUXT_ENV_version=${VERSION} OUTPUT_DIR=dist/${DIR} ROUTER_BASE="/dashboard" RESOURCE_BASE="${BASE}" yarn run build --spa
|
||||
COMMIT=${COMMIT} VERSION=${VERSION} OUTPUT_DIR=dist/${DIR} ROUTER_BASE="/dashboard" RESOURCE_BASE="${BASE}" yarn run build
|
||||
|
|
|
|||
|
|
@ -33,4 +33,4 @@
|
|||
@import "./vendor/vue-select";
|
||||
@import "./vendor/vue-js-modal";
|
||||
@import "./vendor/code-mirror";
|
||||
@import '@/node_modules/xterm/css/xterm.css';
|
||||
@import 'node_modules/xterm/css/xterm.css';
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
font-style: normal;
|
||||
font-weight: normal;
|
||||
src: local(''),
|
||||
url('~shell/assets/fonts/poppins/poppins-v15-latin-300.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~shell/assets/fonts/poppins/poppins-v15-latin-300.woff') format('woff'), /* Modern Browsers */
|
||||
url('~@shell/assets/fonts/poppins/poppins-v15-latin-300.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~@shell/assets/fonts/poppins/poppins-v15-latin-300.woff') format('woff'), /* Modern Browsers */
|
||||
}
|
||||
|
||||
/* poppins-500 - latin */
|
||||
|
|
@ -14,8 +14,8 @@
|
|||
font-style: normal;
|
||||
font-weight: bold;
|
||||
src: local(''),
|
||||
url('~shell/assets/fonts/poppins/poppins-v15-latin-500.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~shell/assets/fonts/poppins/poppins-v15-latin-500.woff') format('woff'), /* Modern Browsers */
|
||||
url('~@shell/assets/fonts/poppins/poppins-v15-latin-500.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~@shell/assets/fonts/poppins/poppins-v15-latin-500.woff') format('woff'), /* Modern Browsers */
|
||||
}
|
||||
|
||||
/* lato-regular - latin */
|
||||
|
|
@ -24,8 +24,8 @@
|
|||
font-style: normal;
|
||||
font-weight: normal;
|
||||
src: local(''),
|
||||
url('~shell/assets/fonts/lato/lato-v17-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~shell/assets/fonts/lato/lato-v17-latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('~@shell/assets/fonts/lato/lato-v17-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~@shell/assets/fonts/lato/lato-v17-latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
}
|
||||
|
||||
/* lato-700 - latin */
|
||||
|
|
@ -34,8 +34,8 @@
|
|||
font-style: normal;
|
||||
font-weight: bold;
|
||||
src: local(''),
|
||||
url('~shell/assets/fonts/lato/lato-v17-latin-700.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~shell/assets/fonts/lato/lato-v17-latin-700.woff') format('woff'), /* Modern Browsers */
|
||||
url('~@shell/assets/fonts/lato/lato-v17-latin-700.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~@shell/assets/fonts/lato/lato-v17-latin-700.woff') format('woff'), /* Modern Browsers */
|
||||
}
|
||||
|
||||
/* roboto-mono-regular - latin */
|
||||
|
|
@ -44,6 +44,6 @@
|
|||
font-style: normal;
|
||||
font-weight: normal;
|
||||
src: local(''),
|
||||
url('~shell/assets/fonts/roboto-mono/roboto-mono-v13-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~shell/assets/fonts/roboto-mono/roboto-mono-v13-latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
}
|
||||
url('~@shell/assets/fonts/roboto-mono/roboto-mono-v13-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('~@shell/assets/fonts/roboto-mono/roboto-mono-v13-latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
@import '~/node_modules/vue-js-modal/dist/styles.css';
|
||||
@import 'node_modules/vue-js-modal/dist/styles.css';
|
||||
|
||||
.v--modal-overlay {
|
||||
background-color: var(--overlay-bg);
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
}
|
||||
|
||||
.v--modal {
|
||||
background-color: var(--modal-bg)!important;
|
||||
background-color: var(--modal-bg) !important;
|
||||
box-shadow: none;
|
||||
border: 2px solid var(--modal-border);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
{ useBuiltIns: false }
|
||||
],
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{ targets: { node: 'current' } }
|
||||
]
|
||||
],
|
||||
env: { test: { presets: [['@babel/env', { targets: { node: 'current' } }]] } }
|
||||
};
|
||||
|
|
@ -1,18 +1 @@
|
|||
module.exports = {
|
||||
env: {
|
||||
test: {
|
||||
plugins: [
|
||||
[
|
||||
'module-resolver',
|
||||
{
|
||||
root: ['.'],
|
||||
alias: {
|
||||
'@': '.',
|
||||
'~': '.',
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
module.exports = require('@rancher/shell/babel.config.js');
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
import config from '@rancher/shell/nuxt.config';
|
||||
|
||||
export default config(__dirname, {
|
||||
excludes: [],
|
||||
autoImport: []
|
||||
});
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* This file is here purely to support using the typescript version of the vue config vue.config.ts.
|
||||
*/
|
||||
require('ts-node').register({
|
||||
project: './tsconfig.json',
|
||||
compilerOptions: { module: 'commonjs' },
|
||||
logError: true
|
||||
});
|
||||
|
||||
module.exports = require('./vue.config.ts').default;
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import config from '@rancher/shell/vue.config';
|
||||
|
||||
export default config(__dirname, {
|
||||
excludes: [],
|
||||
// excludes: ['fleet', 'example']
|
||||
// autoLoad: ['fleet', 'example']
|
||||
});
|
||||
|
|
@ -4,15 +4,15 @@ const path = require('path');
|
|||
const fs = require('fs-extra');
|
||||
|
||||
const targets = {
|
||||
dev: './node_modules/.bin/nuxt dev',
|
||||
nuxt: './node_modules/.bin/nuxt',
|
||||
build: './node_modules/.bin/nuxt build',
|
||||
dev: 'NODE_ENV=dev ./node_modules/.bin/vue-cli-service serve',
|
||||
build: './node_modules/.bin/vue-cli-service build',
|
||||
clean: './node_modules/@rancher/shell/scripts/clean'
|
||||
};
|
||||
|
||||
const files = [
|
||||
'tsconfig.json',
|
||||
'nuxt.config.js',
|
||||
'vue.config.js',
|
||||
'vue.config.ts',
|
||||
'.eslintignore',
|
||||
'.eslintrc.js',
|
||||
'babel.config.js',
|
||||
|
|
@ -25,7 +25,7 @@ console.log('Creating Skeleton Application');
|
|||
const args = process.argv;
|
||||
let appFolder = path.resolve('.');
|
||||
|
||||
if (args.length == 3) {
|
||||
if (args.length === 3) {
|
||||
const name = args[2];
|
||||
const folder = path.resolve('.');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,799 +0,0 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import serveStatic from 'serve-static';
|
||||
import webpack from 'webpack';
|
||||
|
||||
import { STANDARD } from './config/private-label';
|
||||
import { generateDynamicTypeImport } from './pkg/auto-import';
|
||||
import { directiveSsr as t } from './plugins/i18n';
|
||||
import { trimWhitespaceSsr as trimWhitespace } from './plugins/trim-whitespace';
|
||||
|
||||
const createProxyMiddleware = require('http-proxy-middleware');
|
||||
|
||||
// Global variables
|
||||
let api = process.env.API || 'http://localhost:8989';
|
||||
|
||||
if ( !api.startsWith('http') ) {
|
||||
api = `https://${ api }`;
|
||||
}
|
||||
|
||||
// needed for proxies
|
||||
export const API_PATH = api;
|
||||
|
||||
const dev = (process.env.NODE_ENV !== 'production');
|
||||
const devPorts = dev || process.env.DEV_PORTS === 'true';
|
||||
|
||||
// human readable version used on rancher dashboard about page
|
||||
const dashboardVersion = process.env.DASHBOARD_VERSION;
|
||||
|
||||
const prime = process.env.PRIME;
|
||||
|
||||
const pl = process.env.PL || STANDARD;
|
||||
const perfTest = (process.env.PERF_TEST === 'true'); // Enable performance testing when in dev
|
||||
const instrumentCode = (process.env.TEST_INSTRUMENT === 'true'); // Instrument code for code coverage in e2e tests
|
||||
|
||||
// Allow skipping of eslint check
|
||||
// 0 = Skip browser and console checks
|
||||
// 1 = Skip browser check
|
||||
// 2 = Do not skip any checks
|
||||
const skipEsLintCheckStr = (process.env.SKIP_ESLINT || '');
|
||||
let skipEsLintCheck = parseInt(skipEsLintCheckStr, 10) || 2;
|
||||
|
||||
// ===============================================================================================
|
||||
// Nuxt configuration
|
||||
// ===============================================================================================
|
||||
|
||||
// Expose a function that can be used by an app to provide a nuxt configuration for building an application
|
||||
// This takes the directory of the application as tehfirst argument so that we can derive folder locations
|
||||
// from it, rather than from the location of this file
|
||||
export default function(dir, _appConfig) {
|
||||
// Paths to the shell folder when it is included as a node dependency
|
||||
let SHELL = 'node_modules/@rancher/shell';
|
||||
let SHELL_ABS = path.join(dir, 'node_modules/@rancher/shell');
|
||||
let NUXT_SHELL = '~~node_modules/@rancher/shell';
|
||||
let COMPONENTS_DIR = path.join(SHELL_ABS, 'rancher-components');
|
||||
let typescript = {};
|
||||
|
||||
if (fs.existsSync(SHELL_ABS)) {
|
||||
const stat = fs.lstatSync(SHELL_ABS);
|
||||
|
||||
// If @rancher/shell is a symlink, then use the components folder for it
|
||||
if (stat.isSymbolicLink()) {
|
||||
const REAL_SHELL_ABS = fs.realpathSync(SHELL_ABS); // In case the shell is being linked via 'yarn link'
|
||||
|
||||
COMPONENTS_DIR = path.join(REAL_SHELL_ABS, '..', 'pkg', 'rancher-components', 'src', 'components');
|
||||
|
||||
// For now, skip eslint check when being linked via yarn link - pkg folder is linked otherwise
|
||||
// This will change when we remove nuxt
|
||||
skipEsLintCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a local folder named 'shell' then use that rather than the one in node_modules
|
||||
// This will be the case in the main dashboard repository.
|
||||
if (fs.existsSync(path.join(dir, 'shell'))) {
|
||||
SHELL = './shell';
|
||||
SHELL_ABS = path.join(dir, 'shell');
|
||||
NUXT_SHELL = '~~/shell';
|
||||
COMPONENTS_DIR = path.join(dir, 'pkg', 'rancher-components', 'src', 'components');
|
||||
|
||||
// Skip eslint check that runs as part of nuxt build in the console
|
||||
if (skipEsLintCheck > 0) {
|
||||
typescript = { typeCheck: { eslint: { files: './shell/**/*.{ts,js,vue}' } } };
|
||||
}
|
||||
}
|
||||
|
||||
// Instrument code for tests
|
||||
const babelPlugins = [
|
||||
// TODO: Browser support
|
||||
// ['@babel/plugin-transform-modules-commonjs'],
|
||||
['@babel/plugin-proposal-private-property-in-object', { loose: true }]
|
||||
];
|
||||
|
||||
if (instrumentCode) {
|
||||
babelPlugins.push('babel-plugin-istanbul');
|
||||
|
||||
console.warn('Instrumenting code for coverage'); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
// ===============================================================================================
|
||||
// Functions for the UI Plugins
|
||||
// ===============================================================================================
|
||||
|
||||
const appConfig = _appConfig || {};
|
||||
const excludes = appConfig.excludes || [];
|
||||
const autoLoad = appConfig.autoLoad || [];
|
||||
|
||||
const serverMiddleware = [];
|
||||
const autoLoadPackages = [];
|
||||
const watcherIgnores = [
|
||||
/.shell/,
|
||||
/dist-pkg/,
|
||||
/scripts\/standalone/
|
||||
];
|
||||
|
||||
autoLoad.forEach((pkg) => {
|
||||
// Need the version number of each file
|
||||
const pkgPackageFile = require(path.join(dir, 'pkg', pkg, 'package.json'));
|
||||
const pkgRef = `${ pkg }-${ pkgPackageFile.version }`;
|
||||
|
||||
autoLoadPackages.push({
|
||||
name: `app-autoload-${ pkgRef }`,
|
||||
content: `/pkg/${ pkgRef }/${ pkgRef }.umd.min.js`
|
||||
});
|
||||
|
||||
// Anything auto-loaded should also be excluded
|
||||
if (!excludes.includes(pkg)) {
|
||||
excludes.push(pkg);
|
||||
}
|
||||
});
|
||||
|
||||
// Find any UI packages in node_modules
|
||||
const NM = path.join(dir, 'node_modules');
|
||||
const pkg = require(path.join(dir, 'package.json'));
|
||||
const nmPackages = {};
|
||||
|
||||
if (pkg && pkg.dependencies) {
|
||||
Object.keys(pkg.dependencies).forEach((pkg) => {
|
||||
const f = require(path.join(NM, pkg, 'package.json'));
|
||||
|
||||
// The package.json must have the 'rancher' property to mark it as a UI package
|
||||
if (f.rancher) {
|
||||
const id = `${ f.name }-${ f.version }`;
|
||||
|
||||
nmPackages[id] = f.main;
|
||||
|
||||
// Add server middleware to serve up the files for this UI package
|
||||
serverMiddleware.push({
|
||||
path: `/pkg/${ id }`,
|
||||
handler: serveStatic(path.join(NM, pkg))
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
serverMiddleware.push({
|
||||
path: '/uiplugins-catalog',
|
||||
handler: (req, res, next) => {
|
||||
const p = req.url.split('?');
|
||||
|
||||
try {
|
||||
const proxy = createProxyMiddleware({
|
||||
target: p[1],
|
||||
pathRewrite: { '^.*': p[0] }
|
||||
});
|
||||
|
||||
return proxy(req, res, next);
|
||||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function includePkg(name) {
|
||||
if (name.startsWith('.') || name === 'node_modules') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !excludes || (excludes && !excludes.includes(name));
|
||||
}
|
||||
|
||||
excludes.forEach((e) => {
|
||||
watcherIgnores.push(new RegExp(`/pkg.${ e }`));
|
||||
});
|
||||
|
||||
// For each package in the pkg folder that is being compiled into the application,
|
||||
// Add in the code to automatically import the types from that package
|
||||
// This imports models, edit, detail, list etc
|
||||
// When built as a UI package, shell/pkg/vue.config.js does the same thing
|
||||
const autoImportTypes = {};
|
||||
const VirtualModulesPlugin = require('webpack-virtual-modules');
|
||||
let reqs = '';
|
||||
const pkgFolder = path.relative(dir, './pkg');
|
||||
|
||||
if (fs.existsSync(pkgFolder)) {
|
||||
const items = fs.readdirSync(path.relative(dir, './pkg'));
|
||||
|
||||
// Ignore hidden folders
|
||||
items.filter(name => !name.startsWith('.')).forEach((name) => {
|
||||
const f = require(path.join(dir, 'pkg', name, 'package.json'));
|
||||
|
||||
// Package file must have rancher field to be a plugin
|
||||
if (includePkg(name) && f.rancher) {
|
||||
reqs += `$plugin.initPlugin('${ name }', require(\'~/pkg/${ name }\')); `;
|
||||
|
||||
// // Serve the code for the UI package in case its used for dynamic loading (but not if the same package was provided in node_modules)
|
||||
// if (!nmPackages[name]) {
|
||||
// const pkgPackageFile = require(path.join(dir, 'pkg', name, 'package.json'));
|
||||
// const pkgRef = `${ name }-${ pkgPackageFile.version }`;
|
||||
|
||||
// serverMiddleware.push({ path: `/pkg/${ pkgRef }`, handler: serveStatic(`${ dir }/dist-pkg/${ pkgRef }`) });
|
||||
// }
|
||||
autoImportTypes[`@rancher/auto-import/${ name }`] = generateDynamicTypeImport(`@pkg/${ name }`, path.join(dir, `pkg/${ name }`));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(nmPackages).forEach((m) => {
|
||||
reqs += `$plugin.loadAsync('${ m }', '/pkg/${ m }/${ nmPackages[m] }');`;
|
||||
});
|
||||
|
||||
// Generate a virtual module '@rancher/dyanmic.js` which imports all of the packages that should be built into the application
|
||||
// This is imported in 'shell/extensions/extension-loader.js` which ensures the all code for plugins to be included is imported in the application
|
||||
const virtualModules = new VirtualModulesPlugin({ 'node_modules/@rancher/dynamic.js': `export default function ($plugin) { ${ reqs } };` });
|
||||
const autoImport = new webpack.NormalModuleReplacementPlugin(/^@rancher\/auto-import$/, (resource) => {
|
||||
const ctx = resource.context.split('/');
|
||||
const pkg = ctx[ctx.length - 1];
|
||||
|
||||
resource.request = `@rancher/auto-import/${ pkg }`;
|
||||
});
|
||||
|
||||
// @pkg imports must be resolved to the package that it importing them - this allows a package to use @pkg as an alis
|
||||
// to the root of that particular package
|
||||
const pkgImport = new webpack.NormalModuleReplacementPlugin(/^@pkg/, (resource) => {
|
||||
const ctx = resource.context.split('/');
|
||||
// Find 'pkg' folder in the contxt
|
||||
const index = ctx.findIndex(s => s === 'pkg');
|
||||
|
||||
if (index !== -1 && (index + 1) < ctx.length) {
|
||||
const pkg = ctx[index + 1];
|
||||
let p = path.resolve(dir, 'pkg', pkg, resource.request.substr(5));
|
||||
|
||||
if (resource.request.startsWith(`@pkg/${ pkg }`)) {
|
||||
p = path.resolve(dir, 'pkg', resource.request.substr(5));
|
||||
}
|
||||
|
||||
resource.request = p;
|
||||
}
|
||||
});
|
||||
|
||||
// Serve up the dist-pkg folder under /pkg
|
||||
serverMiddleware.push({ path: `/pkg/`, handler: serveStatic(`${ dir }/dist-pkg/`) });
|
||||
// Add the standard dashboard server middleware after the middleware added to serve up UI packages
|
||||
serverMiddleware.push(path.resolve(dir, SHELL, 'server', 'server-middleware'));
|
||||
|
||||
// ===============================================================================================
|
||||
// Dashboard nuxt configuration
|
||||
// ===============================================================================================
|
||||
|
||||
require('events').EventEmitter.defaultMaxListeners = 20;
|
||||
require('dotenv').config();
|
||||
|
||||
let routerBasePath = '/';
|
||||
let resourceBase = '';
|
||||
let outputDir = 'dist';
|
||||
|
||||
if ( typeof process.env.ROUTER_BASE !== 'undefined' ) {
|
||||
routerBasePath = process.env.ROUTER_BASE;
|
||||
}
|
||||
|
||||
if ( typeof process.env.RESOURCE_BASE !== 'undefined' ) {
|
||||
resourceBase = process.env.RESOURCE_BASE;
|
||||
}
|
||||
|
||||
if ( typeof process.env.OUTPUT_DIR !== 'undefined' ) {
|
||||
outputDir = process.env.OUTPUT_DIR;
|
||||
}
|
||||
|
||||
if ( resourceBase && !resourceBase.endsWith('/') ) {
|
||||
resourceBase += '/';
|
||||
}
|
||||
|
||||
console.log(`Build: ${ dev ? 'Development' : 'Production' }`); // eslint-disable-line no-console
|
||||
|
||||
if ( !dev ) {
|
||||
console.log(`Version: ${ dashboardVersion }`); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if ( resourceBase ) {
|
||||
console.log(`Resource Base URL: ${ resourceBase }`); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if ( routerBasePath !== '/' ) {
|
||||
console.log(`Router Base Path: ${ routerBasePath }`); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if ( pl !== STANDARD ) {
|
||||
console.log(`PL: ${ pl }`); // eslint-disable-line no-console
|
||||
}
|
||||
const rancherEnv = process.env.RANCHER_ENV || 'web';
|
||||
|
||||
console.log(`API: '${ api }'. Env: '${ rancherEnv }'`); // eslint-disable-line no-console
|
||||
|
||||
// Nuxt modules
|
||||
let nuxtModules = [
|
||||
'@nuxtjs/proxy',
|
||||
'@nuxtjs/axios',
|
||||
'@nuxtjs/eslint-module',
|
||||
'@nuxtjs/webpack-profile',
|
||||
'cookie-universal-nuxt',
|
||||
'portal-vue/nuxt',
|
||||
path.join(NUXT_SHELL, 'plugins/dashboard-store/rehydrate-all'),
|
||||
];
|
||||
|
||||
// Remove es-lint nuxt module if env var configures this
|
||||
if (skipEsLintCheck < 2) {
|
||||
nuxtModules = nuxtModules.filter(s => !s.includes('eslint-module'));
|
||||
}
|
||||
|
||||
const config = {
|
||||
dev,
|
||||
|
||||
// Configuration visible to the client, https://nuxtjs.org/api/configuration-env
|
||||
env: {
|
||||
dev,
|
||||
pl,
|
||||
perfTest,
|
||||
rancherEnv,
|
||||
harvesterPkgUrl: process.env.HARVESTER_PKG_URL,
|
||||
api
|
||||
},
|
||||
|
||||
// vars accessible via this.$config https://nuxtjs.org/docs/configuration-glossary/configuration-runtime-config/
|
||||
publicRuntimeConfig: { rancherEnv, dashboardVersion },
|
||||
|
||||
buildDir: dev ? '.nuxt' : '.nuxt-prod',
|
||||
|
||||
buildModules: [
|
||||
'@nuxtjs/style-resources',
|
||||
'@nuxt/typescript-build'
|
||||
],
|
||||
styleResources: {
|
||||
// only import functions, mixins, or variables, NEVER import full styles https://github.com/nuxt-community/style-resources-module#warning
|
||||
hoistUseStatements: true,
|
||||
scss: [
|
||||
path.resolve(SHELL_ABS, 'assets/styles/base/_variables.scss'),
|
||||
path.resolve(SHELL_ABS, 'assets/styles/base/_functions.scss'),
|
||||
path.resolve(SHELL_ABS, 'assets/styles/base/_mixins.scss'),
|
||||
],
|
||||
},
|
||||
|
||||
loadingIndicator: path.join(SHELL_ABS, 'static/loading-indicator.html'),
|
||||
|
||||
loading: path.join(SHELL_ABS, 'components/nav/GlobalLoading.vue'),
|
||||
|
||||
// Axios: https://axios.nuxtjs.org/options
|
||||
axios: {
|
||||
https: true,
|
||||
proxy: true,
|
||||
retry: { retries: 0 },
|
||||
// debug: true
|
||||
},
|
||||
|
||||
content: {
|
||||
dir: path.resolve(SHELL_ABS, 'content'),
|
||||
markdown: { prism: { theme: false } },
|
||||
liveEdit: false
|
||||
},
|
||||
|
||||
router: {
|
||||
base: routerBasePath,
|
||||
middleware: ['i18n'],
|
||||
prefetchLinks: false
|
||||
},
|
||||
|
||||
alias: {
|
||||
'~shell': SHELL_ABS,
|
||||
'@shell': SHELL_ABS,
|
||||
'@pkg': path.join(dir, 'pkg'),
|
||||
'@components': COMPONENTS_DIR,
|
||||
},
|
||||
|
||||
modulesDir: [
|
||||
path.resolve(dir),
|
||||
'./node_modules',
|
||||
SHELL_ABS
|
||||
],
|
||||
|
||||
dir: {
|
||||
assets: path.posix.join(SHELL, 'assets'),
|
||||
layouts: path.posix.join(SHELL, 'layouts'),
|
||||
middleware: path.posix.join(SHELL, 'middleware'),
|
||||
pages: path.posix.join(SHELL, 'pages'),
|
||||
static: path.posix.join(SHELL, 'static'),
|
||||
store: path.posix.join(SHELL, 'store'),
|
||||
},
|
||||
|
||||
watchers: { webpack: { ignore: watcherIgnores } },
|
||||
|
||||
build: {
|
||||
publicPath: resourceBase,
|
||||
parallel: true,
|
||||
cache: true,
|
||||
hardSource: true,
|
||||
|
||||
// Uses the Webpack Build Analyzer to generate a report of the bundle contents
|
||||
// analyze: { analyzerMode: 'static' },
|
||||
|
||||
uglify: {
|
||||
uglifyOptions: { compress: !dev },
|
||||
cache: './node_modules/.cache/uglify'
|
||||
},
|
||||
|
||||
'html.minify': {
|
||||
collapseBooleanAttributes: !dev,
|
||||
decodeEntities: !dev,
|
||||
minifyCSS: !dev,
|
||||
minifyJS: !dev,
|
||||
processConditionalComments: !dev,
|
||||
removeEmptyAttributes: !dev,
|
||||
removeRedundantAttributes: !dev,
|
||||
trimCustomFragments: !dev,
|
||||
useShortDoctype: !dev
|
||||
},
|
||||
|
||||
// Don't include `[name]` in prod file names
|
||||
// This flattens out the folder structure (avoids crazy paths like `_nuxt/pages/account/create-key/pages/c/_cluster/_product/_resource/_id/pages/c/_cluster/_product/_resource`)
|
||||
// and uses nuxt's workaround to address issues with filenames containing `//` (see https://github.com/nuxt/nuxt.js/issues/8274)
|
||||
filenames: { chunk: ({ isDev }) => isDev ? '[name].js' : '[contenthash].js' },
|
||||
// @TODO figure out how to split chunks up better, by product
|
||||
// optimization: {
|
||||
// splitChunks: {
|
||||
// cacheGroups: {
|
||||
// styles: {
|
||||
// name: 'styles',
|
||||
// test: /\.(css|vue)$/,
|
||||
// chunks: 'all',
|
||||
// enforce: true
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
|
||||
plugins: [
|
||||
virtualModules,
|
||||
autoImport,
|
||||
new VirtualModulesPlugin(autoImportTypes),
|
||||
pkgImport,
|
||||
],
|
||||
|
||||
extend(config, { isClient, isDev }) {
|
||||
if ( isDev ) {
|
||||
config.devtool = 'cheap-module-source-map';
|
||||
} else {
|
||||
config.devtool = 'source-map';
|
||||
}
|
||||
|
||||
if ( resourceBase ) {
|
||||
config.output.publicPath = resourceBase;
|
||||
}
|
||||
|
||||
// Remove default image handling rules
|
||||
for ( let i = config.module.rules.length - 1 ; i >= 0 ; i-- ) {
|
||||
if ( /svg/.test(config.module.rules[i].test) ) {
|
||||
config.module.rules.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
config.resolve.symlinks = false;
|
||||
|
||||
// Ensure we process files in the @rancher/shell folder
|
||||
config.module.rules.forEach((r) => {
|
||||
if ('test.js'.match(r.test)) {
|
||||
if (r.exclude) {
|
||||
const orig = r.exclude;
|
||||
|
||||
r.exclude = function(modulePath) {
|
||||
if (modulePath.indexOf(SHELL_ABS) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return orig(modulePath);
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// And substitute our own loader for images
|
||||
config.module.rules.unshift({
|
||||
test: /\.(png|jpe?g|gif|svg|webp)$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
name: '[path][name].[ext]',
|
||||
limit: 1,
|
||||
esModule: false
|
||||
},
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Handler for yaml files (used for i18n files, for example)
|
||||
config.module.rules.unshift({
|
||||
test: /\.ya?ml$/i,
|
||||
loader: 'js-yaml-loader',
|
||||
options: { name: '[path][name].[ext]' },
|
||||
});
|
||||
|
||||
// Handler for csv files (e.g. ec2 instance data)
|
||||
config.module.rules.unshift({
|
||||
test: /\.csv$/i,
|
||||
loader: 'csv-loader',
|
||||
options: {
|
||||
dynamicTyping: true,
|
||||
header: true,
|
||||
skipEmptyLines: true
|
||||
},
|
||||
});
|
||||
|
||||
// Ensure there is a fallback for browsers that don't support web workers
|
||||
config.module.rules.unshift({
|
||||
test: /web-worker.[a-z-]+.js/i,
|
||||
loader: 'worker-loader',
|
||||
options: { inline: 'fallback' },
|
||||
});
|
||||
|
||||
// Prevent warning in log with the md files in the content folder
|
||||
config.module.rules.push({
|
||||
test: /\.md$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'frontmatter-markdown-loader',
|
||||
options: { mode: ['body'] }
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
|
||||
// extractCSS: true,
|
||||
cssSourceMap: true,
|
||||
babel: {
|
||||
presets({ isServer }) {
|
||||
return [
|
||||
[
|
||||
require.resolve('@nuxt/babel-preset-app'),
|
||||
{
|
||||
// buildTarget: isServer ? 'server' : 'client',
|
||||
corejs: { version: 3 },
|
||||
targets: isServer ? { node: '12' } : { browsers: ['last 2 versions'] },
|
||||
modern: !isServer
|
||||
}
|
||||
],
|
||||
'@babel/preset-typescript',
|
||||
];
|
||||
},
|
||||
plugins: babelPlugins
|
||||
}
|
||||
},
|
||||
|
||||
render: {
|
||||
bundleRenderer: {
|
||||
directives: {
|
||||
trimWhitespace,
|
||||
t,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// modern: true, -- now part of preset above
|
||||
|
||||
generate: { dir: outputDir },
|
||||
|
||||
// Global CSS
|
||||
css: [
|
||||
path.resolve(SHELL_ABS, 'assets/styles/app.scss')
|
||||
],
|
||||
|
||||
head: {
|
||||
title: process.env.npm_package_name || '',
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{
|
||||
hid: 'description',
|
||||
name: 'description',
|
||||
content: process.env.npm_package_description || ''
|
||||
},
|
||||
...autoLoadPackages,
|
||||
],
|
||||
link: [{
|
||||
hid: 'icon',
|
||||
rel: 'icon',
|
||||
type: 'image/x-icon',
|
||||
href: `${ resourceBase || '/' }favicon.png`
|
||||
}]
|
||||
},
|
||||
|
||||
// Nuxt modules
|
||||
modules: nuxtModules,
|
||||
|
||||
// Vue plugins
|
||||
plugins: [
|
||||
// Extensions
|
||||
path.relative(dir, path.join(SHELL, 'core/plugins.js')),
|
||||
path.relative(dir, path.join(SHELL, 'core/plugins-loader.js')), // Load builtin plugins
|
||||
|
||||
// Third-party
|
||||
path.join(NUXT_SHELL, 'plugins/axios'),
|
||||
path.join(NUXT_SHELL, 'plugins/tooltip'),
|
||||
path.join(NUXT_SHELL, 'plugins/vue-clipboard2'),
|
||||
path.join(NUXT_SHELL, 'plugins/v-select'),
|
||||
path.join(NUXT_SHELL, 'plugins/directives'),
|
||||
path.join(NUXT_SHELL, 'plugins/transitions'),
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/vue-js-modal') },
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/js-yaml'), ssr: false },
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/resize'), ssr: false },
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/shortkey'), ssr: false },
|
||||
|
||||
// First-party
|
||||
path.join(NUXT_SHELL, 'plugins/i18n'),
|
||||
path.join(NUXT_SHELL, 'plugins/global-formatters'),
|
||||
path.join(NUXT_SHELL, 'plugins/trim-whitespace'),
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/extend-router') },
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/console'), ssr: false },
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/int-number'), ssr: false },
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/nuxt-client-init'), ssr: false },
|
||||
path.join(NUXT_SHELL, 'plugins/replaceall'),
|
||||
path.join(NUXT_SHELL, 'plugins/back-button'),
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/plugin'), ssr: false }, // Load dyanmic plugins
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/codemirror-loader'), ssr: false },
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/formatters'), ssr: false }, // Populate formatters cache for sorted table
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/version'), ssr: false }, // Makes a fetch to the backend to get version metadata
|
||||
{ src: path.join(NUXT_SHELL, 'plugins/steve-create-worker'), ssr: false }, // Add steve web worker creator to the store, to break the import chain
|
||||
],
|
||||
|
||||
// Proxy: https://github.com/nuxt-community/proxy-module#options
|
||||
proxy: {
|
||||
...appConfig.proxies,
|
||||
'/k8s': proxyWsOpts(api), // Straight to a remote cluster (/k8s/clusters/<id>/)
|
||||
'/pp': proxyWsOpts(api), // For (epinio) standalone API
|
||||
'/api': proxyWsOpts(api), // Management k8s API
|
||||
'/apis': proxyWsOpts(api), // Management k8s API
|
||||
'/v1': proxyWsOpts(api), // Management Steve API
|
||||
'/v3': proxyWsOpts(api), // Rancher API
|
||||
'/v3-public': proxyOpts(api), // Rancher Unauthed API
|
||||
'/api-ui': proxyOpts(api), // Browser API UI
|
||||
'/meta': proxyMetaOpts(api), // Browser API UI
|
||||
'/v1-*': proxyOpts(api), // SAML, KDM, etc
|
||||
'/rancherversion': proxyPrimeOpts(api), // Rancher version endpoint
|
||||
// These are for Ember embedding
|
||||
'/c/*/edit': proxyOpts('https://127.0.0.1:8000'), // Can't proxy all of /c because that's used by Vue too
|
||||
'/k/': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/g/': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/n/': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/p/': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/assets': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/translations': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/engines-dist': proxyOpts('https://127.0.0.1:8000'),
|
||||
},
|
||||
|
||||
// Nuxt server
|
||||
server: {
|
||||
https: (devPorts ? {
|
||||
key: fs.readFileSync(path.resolve(dir, SHELL, 'server/server.key')),
|
||||
cert: fs.readFileSync(path.resolve(dir, SHELL, 'server/server.crt'))
|
||||
} : null),
|
||||
port: (devPorts ? 8005 : 80),
|
||||
host: '0.0.0.0',
|
||||
},
|
||||
|
||||
// Server middleware
|
||||
serverMiddleware,
|
||||
|
||||
// Eslint module options
|
||||
eslint: {
|
||||
cache: path.join(dir, 'node_modules/.cache/eslint'),
|
||||
exclude: [
|
||||
'.nuxt'
|
||||
]
|
||||
},
|
||||
|
||||
// Typescript eslint
|
||||
typescript,
|
||||
|
||||
ssr: false,
|
||||
};
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// ===============================================================================================
|
||||
// Functions for the request proxying used in dev
|
||||
// ===============================================================================================
|
||||
|
||||
export function proxyMetaOpts(target) {
|
||||
return {
|
||||
target,
|
||||
followRedirects: true,
|
||||
secure: !dev,
|
||||
onProxyReq,
|
||||
onProxyReqWs,
|
||||
onError,
|
||||
onProxyRes,
|
||||
};
|
||||
}
|
||||
|
||||
export function proxyOpts(target) {
|
||||
return {
|
||||
target,
|
||||
secure: !devPorts,
|
||||
onProxyReq,
|
||||
onProxyReqWs,
|
||||
onError,
|
||||
onProxyRes,
|
||||
};
|
||||
}
|
||||
|
||||
// Intercept the /rancherversion API call wnad modify the 'RancherPrime' value
|
||||
// if configured to do so by the environment variable PRIME
|
||||
export function proxyPrimeOpts(target) {
|
||||
const opts = proxyOpts(target);
|
||||
|
||||
// Don't intercept if the PRIME environment variable is not set
|
||||
if (!prime?.length) {
|
||||
return opts;
|
||||
}
|
||||
|
||||
opts.onProxyRes = (proxyRes, req, res) => {
|
||||
const _end = res.end;
|
||||
let body = '';
|
||||
|
||||
proxyRes.on( 'data', (data) => {
|
||||
data = data.toString('utf-8');
|
||||
body += data;
|
||||
});
|
||||
|
||||
res.write = () => {};
|
||||
|
||||
res.end = () => {
|
||||
let output = body;
|
||||
|
||||
try {
|
||||
const out = JSON.parse(body);
|
||||
|
||||
out.RancherPrime = prime;
|
||||
output = JSON.stringify(out);
|
||||
} catch (err) {}
|
||||
|
||||
res.setHeader('content-length', output.length );
|
||||
res.setHeader('content-type', 'application/json' );
|
||||
res.setHeader('transfer-encoding', '');
|
||||
res.setHeader('cache-control', 'no-cache');
|
||||
res.writeHead(proxyRes.statusCode);
|
||||
_end.apply(res, [output]);
|
||||
};
|
||||
};
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
export function onProxyRes(proxyRes, req, res) {
|
||||
if (devPorts) {
|
||||
proxyRes.headers['X-Frame-Options'] = 'ALLOWALL';
|
||||
}
|
||||
}
|
||||
|
||||
export function proxyWsOpts(target) {
|
||||
return {
|
||||
...proxyOpts(target),
|
||||
ws: true,
|
||||
changeOrigin: true,
|
||||
};
|
||||
}
|
||||
|
||||
export function onProxyReq(proxyReq, req) {
|
||||
if (!(proxyReq._currentRequest && proxyReq._currentRequest._headerSent)) {
|
||||
proxyReq.setHeader('x-api-host', req.headers['host']);
|
||||
proxyReq.setHeader('x-forwarded-proto', 'https');
|
||||
// console.log(proxyReq.getHeaders());
|
||||
}
|
||||
}
|
||||
|
||||
export function onProxyReqWs(proxyReq, req, socket, options, head) {
|
||||
req.headers.origin = options.target.href;
|
||||
proxyReq.setHeader('origin', options.target.href);
|
||||
proxyReq.setHeader('x-api-host', req.headers['host']);
|
||||
proxyReq.setHeader('x-forwarded-proto', 'https');
|
||||
// console.log(proxyReq.getHeaders());
|
||||
|
||||
socket.on('error', (err) => {
|
||||
console.error('Proxy WS Error:', err); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
|
||||
export function onError(err, req, res) {
|
||||
res.statusCode = 598;
|
||||
console.error('Proxy Error:', err); // eslint-disable-line no-console
|
||||
res.write(JSON.stringify(err));
|
||||
}
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
import Vue from 'vue'
|
||||
import { decode, parsePath, withoutBase, withoutTrailingSlash, normalizeURL } from 'ufo'
|
||||
|
||||
import { getMatchedComponentsInstances, getChildrenComponentInstancesUsingFetch, promisify, globalHandleError, urlJoin, sanitizeComponent } from './utils'
|
||||
import NuxtError from '../layouts/error.vue'
|
||||
import NuxtLoading from '../components/nav/GlobalLoading.vue'
|
||||
import NuxtBuildIndicator from './components/nuxt-build-indicator'
|
||||
|
||||
import '../assets/styles/app.scss'
|
||||
|
||||
import _77180f1e from '../layouts/blank.vue'
|
||||
import _6f6c098b from '../layouts/default.vue'
|
||||
import _2d2495d5 from '../layouts/home.vue'
|
||||
import _77dd5794 from '../layouts/plain.vue'
|
||||
import _44002f80 from '../layouts/unauthenticated.vue'
|
||||
|
||||
const layouts = { "_blank": sanitizeComponent(_77180f1e),"_default": sanitizeComponent(_6f6c098b),"_home": sanitizeComponent(_2d2495d5),"_plain": sanitizeComponent(_77dd5794),"_unauthenticated": sanitizeComponent(_44002f80) }
|
||||
|
||||
export default {
|
||||
render (h, props) {
|
||||
const loadingEl = h('NuxtLoading', { ref: 'loading' })
|
||||
|
||||
const layoutEl = h(this.layout || 'nuxt')
|
||||
const templateEl = h('div', {
|
||||
domProps: {
|
||||
id: '__layout'
|
||||
},
|
||||
key: this.layoutName
|
||||
}, [layoutEl])
|
||||
|
||||
const transitionEl = h('transition', {
|
||||
props: {
|
||||
name: 'layout',
|
||||
mode: 'out-in'
|
||||
},
|
||||
on: {
|
||||
beforeEnter (el) {
|
||||
// Ensure to trigger scroll event after calling scrollBehavior
|
||||
window.$nuxt.$nextTick(() => {
|
||||
window.$nuxt.$emit('triggerScroll')
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [templateEl])
|
||||
|
||||
return h('div', {
|
||||
domProps: {
|
||||
id: '__nuxt'
|
||||
}
|
||||
}, [
|
||||
loadingEl,
|
||||
//h(NuxtBuildIndicator), // The build indicator doesn't work as is right now and emits an error in the console so I'm leaving it out for now
|
||||
transitionEl
|
||||
])
|
||||
},
|
||||
|
||||
data: () => ({
|
||||
isOnline: true,
|
||||
|
||||
layout: null,
|
||||
layoutName: '',
|
||||
|
||||
nbFetching: 0
|
||||
}),
|
||||
|
||||
beforeCreate () {
|
||||
Vue.util.defineReactive(this, 'nuxt', this.$options.nuxt)
|
||||
},
|
||||
created () {
|
||||
// Add this.$nuxt in child instances
|
||||
this.$root.$options.$nuxt = this
|
||||
|
||||
if (process.client) {
|
||||
// add to window so we can listen when ready
|
||||
window.$nuxt = this
|
||||
|
||||
this.refreshOnlineStatus()
|
||||
// Setup the listeners
|
||||
window.addEventListener('online', this.refreshOnlineStatus)
|
||||
window.addEventListener('offline', this.refreshOnlineStatus)
|
||||
}
|
||||
// Add $nuxt.error()
|
||||
this.error = this.nuxt.error
|
||||
// Add $nuxt.context
|
||||
this.context = this.$options.context
|
||||
},
|
||||
|
||||
async mounted () {
|
||||
this.$loading = this.$refs.loading
|
||||
},
|
||||
|
||||
watch: {
|
||||
'nuxt.err': 'errorChanged'
|
||||
},
|
||||
|
||||
computed: {
|
||||
isOffline () {
|
||||
return !this.isOnline
|
||||
},
|
||||
|
||||
isFetching () {
|
||||
return this.nbFetching > 0
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
refreshOnlineStatus () {
|
||||
if (process.client) {
|
||||
if (typeof window.navigator.onLine === 'undefined') {
|
||||
// If the browser doesn't support connection status reports
|
||||
// assume that we are online because most apps' only react
|
||||
// when they now that the connection has been interrupted
|
||||
this.isOnline = true
|
||||
} else {
|
||||
this.isOnline = window.navigator.onLine
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async refresh () {
|
||||
const pages = getMatchedComponentsInstances(this.$route)
|
||||
|
||||
if (!pages.length) {
|
||||
return
|
||||
}
|
||||
this.$loading.start()
|
||||
|
||||
const promises = pages.map((page) => {
|
||||
const p = []
|
||||
|
||||
// Old fetch
|
||||
if (page.$options.fetch && page.$options.fetch.length) {
|
||||
p.push(promisify(page.$options.fetch, this.context))
|
||||
}
|
||||
if (page.$fetch) {
|
||||
p.push(page.$fetch())
|
||||
} else {
|
||||
// Get all component instance to call $fetch
|
||||
for (const component of getChildrenComponentInstancesUsingFetch(page.$vnode.componentInstance)) {
|
||||
p.push(component.$fetch())
|
||||
}
|
||||
}
|
||||
|
||||
if (page.$options.asyncData) {
|
||||
p.push(
|
||||
promisify(page.$options.asyncData, this.context)
|
||||
.then((newData) => {
|
||||
for (const key in newData) {
|
||||
Vue.set(page.$data, key, newData[key])
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
return Promise.all(p)
|
||||
})
|
||||
try {
|
||||
await Promise.all(promises)
|
||||
} catch (error) {
|
||||
this.$loading.fail(error)
|
||||
globalHandleError(error)
|
||||
this.error(error)
|
||||
}
|
||||
this.$loading.finish()
|
||||
},
|
||||
errorChanged () {
|
||||
if (this.nuxt.err) {
|
||||
if (this.$loading) {
|
||||
if (this.$loading.fail) {
|
||||
this.$loading.fail(this.nuxt.err)
|
||||
}
|
||||
if (this.$loading.finish) {
|
||||
this.$loading.finish()
|
||||
}
|
||||
}
|
||||
|
||||
let errorLayout = (NuxtError.options || NuxtError).layout;
|
||||
|
||||
if (typeof errorLayout === 'function') {
|
||||
errorLayout = errorLayout(this.context)
|
||||
}
|
||||
|
||||
this.setLayout(errorLayout)
|
||||
}
|
||||
},
|
||||
|
||||
setLayout (layout) {
|
||||
if(layout && typeof layout !== 'string') {
|
||||
throw new Error('[nuxt] Avoid using non-string value as layout property.')
|
||||
}
|
||||
|
||||
if (!layout || !layouts['_' + layout]) {
|
||||
layout = 'default'
|
||||
}
|
||||
this.layoutName = layout
|
||||
this.layout = layouts['_' + layout]
|
||||
return this.layout
|
||||
},
|
||||
loadLayout (layout) {
|
||||
if (!layout || !layouts['_' + layout]) {
|
||||
layout = 'default'
|
||||
}
|
||||
return Promise.resolve(layouts['_' + layout])
|
||||
},
|
||||
},
|
||||
|
||||
components: {
|
||||
NuxtLoading
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
import Axios from 'axios'
|
||||
import defu from 'defu'
|
||||
import axiosRetry from 'axios-retry'
|
||||
|
||||
// Axios.prototype cannot be modified
|
||||
const axiosExtra = {
|
||||
setBaseURL (baseURL) {
|
||||
this.defaults.baseURL = baseURL
|
||||
},
|
||||
setHeader (name, value, scopes = 'common') {
|
||||
for (let scope of Array.isArray(scopes) ? scopes : [ scopes ]) {
|
||||
if (!value) {
|
||||
delete this.defaults.headers[scope][name];
|
||||
return
|
||||
}
|
||||
this.defaults.headers[scope][name] = value
|
||||
}
|
||||
},
|
||||
setToken (token, type, scopes = 'common') {
|
||||
const value = !token ? null : (type ? type + ' ' : '') + token
|
||||
this.setHeader('Authorization', value, scopes)
|
||||
},
|
||||
onRequest(fn) {
|
||||
this.interceptors.request.use(config => fn(config) || config)
|
||||
},
|
||||
onResponse(fn) {
|
||||
this.interceptors.response.use(response => fn(response) || response)
|
||||
},
|
||||
onRequestError(fn) {
|
||||
this.interceptors.request.use(undefined, error => fn(error) || Promise.reject(error))
|
||||
},
|
||||
onResponseError(fn) {
|
||||
this.interceptors.response.use(undefined, error => fn(error) || Promise.reject(error))
|
||||
},
|
||||
onError(fn) {
|
||||
this.onRequestError(fn)
|
||||
this.onResponseError(fn)
|
||||
},
|
||||
create(options) {
|
||||
return createAxiosInstance(defu(options, this.defaults))
|
||||
}
|
||||
}
|
||||
|
||||
// Request helpers ($get, $post, ...)
|
||||
for (let method of ['request', 'delete', 'get', 'head', 'options', 'post', 'put', 'patch']) {
|
||||
axiosExtra['$' + method] = function () { return this[method].apply(this, arguments).then(res => res && res.data) }
|
||||
}
|
||||
|
||||
const extendAxiosInstance = axios => {
|
||||
for (let key in axiosExtra) {
|
||||
axios[key] = axiosExtra[key].bind(axios)
|
||||
}
|
||||
}
|
||||
|
||||
const createAxiosInstance = axiosOptions => {
|
||||
// Create new axios instance
|
||||
const axios = Axios.create(axiosOptions)
|
||||
axios.CancelToken = Axios.CancelToken
|
||||
axios.isCancel = Axios.isCancel
|
||||
|
||||
// Extend axios proto
|
||||
extendAxiosInstance(axios)
|
||||
|
||||
// Setup interceptors
|
||||
|
||||
setupProgress(axios)
|
||||
axiosRetry(axios, {"retries":0})
|
||||
|
||||
return axios
|
||||
}
|
||||
|
||||
const setupProgress = (axios) => {
|
||||
if (process.server) {
|
||||
return
|
||||
}
|
||||
|
||||
// A noop loading inteterface for when $nuxt is not yet ready
|
||||
const noopLoading = {
|
||||
finish: () => { },
|
||||
start: () => { },
|
||||
fail: () => { },
|
||||
set: () => { }
|
||||
}
|
||||
|
||||
const $loading = () => {
|
||||
const $nuxt = typeof window !== 'undefined' && window['$nuxt']
|
||||
return ($nuxt && $nuxt.$loading && $nuxt.$loading.set) ? $nuxt.$loading : noopLoading
|
||||
}
|
||||
|
||||
let currentRequests = 0
|
||||
|
||||
axios.onRequest(config => {
|
||||
if (config && config.progress === false) {
|
||||
return
|
||||
}
|
||||
|
||||
currentRequests++
|
||||
})
|
||||
|
||||
axios.onResponse(response => {
|
||||
if (response && response.config && response.config.progress === false) {
|
||||
return
|
||||
}
|
||||
|
||||
currentRequests--
|
||||
if (currentRequests <= 0) {
|
||||
currentRequests = 0
|
||||
$loading().finish()
|
||||
}
|
||||
})
|
||||
|
||||
axios.onError(error => {
|
||||
if (error && error.config && error.config.progress === false) {
|
||||
return
|
||||
}
|
||||
|
||||
currentRequests--
|
||||
|
||||
if (Axios.isCancel(error)) {
|
||||
return
|
||||
}
|
||||
|
||||
$loading().fail()
|
||||
$loading().finish()
|
||||
})
|
||||
|
||||
const onProgress = e => {
|
||||
if (!currentRequests) {
|
||||
return
|
||||
}
|
||||
const progress = ((e.loaded * 100) / (e.total * currentRequests))
|
||||
$loading().set(Math.min(100, progress))
|
||||
}
|
||||
|
||||
axios.defaults.onUploadProgress = onProgress
|
||||
axios.defaults.onDownloadProgress = onProgress
|
||||
}
|
||||
|
||||
export default (ctx, inject) => {
|
||||
// runtimeConfig
|
||||
const runtimeConfig = ctx.$config && ctx.$config.axios || {}
|
||||
// baseURL
|
||||
const baseURL = process.browser
|
||||
? (runtimeConfig.browserBaseURL || runtimeConfig.baseURL || '/')
|
||||
: (runtimeConfig.baseURL || process.env._AXIOS_BASE_URL_ || 'https://localhost:8005/')
|
||||
|
||||
// Create fresh objects for all default header scopes
|
||||
// Axios creates only one which is shared across SSR requests!
|
||||
// https://github.com/mzabriskie/axios/blob/master/lib/defaults.js
|
||||
const headers = {
|
||||
"common": {
|
||||
"Accept": "application/json, text/plain, */*"
|
||||
},
|
||||
"delete": {},
|
||||
"get": {},
|
||||
"head": {},
|
||||
"post": {},
|
||||
"put": {},
|
||||
"patch": {}
|
||||
}
|
||||
|
||||
const axiosOptions = {
|
||||
baseURL,
|
||||
headers
|
||||
}
|
||||
|
||||
// Proxy SSR request headers headers
|
||||
if (process.server && ctx.req && ctx.req.headers) {
|
||||
const reqHeaders = { ...ctx.req.headers }
|
||||
for (let h of ["accept","host","cf-ray","cf-connecting-ip","content-length","content-md5","content-type"]) {
|
||||
delete reqHeaders[h]
|
||||
}
|
||||
axiosOptions.headers.common = { ...reqHeaders, ...axiosOptions.headers.common }
|
||||
}
|
||||
|
||||
if (process.server) {
|
||||
// Don't accept brotli encoding because Node can't parse it
|
||||
axiosOptions.headers.common['accept-encoding'] = 'gzip, deflate'
|
||||
}
|
||||
|
||||
const axios = createAxiosInstance(axiosOptions)
|
||||
|
||||
// Inject axios to the context as $axios
|
||||
ctx.$axios = axios
|
||||
inject('axios', axios)
|
||||
}
|
||||
|
|
@ -0,0 +1,817 @@
|
|||
import Vue from 'vue'
|
||||
import fetch from 'unfetch'
|
||||
import middleware from './middleware.js'
|
||||
import {
|
||||
applyAsyncData,
|
||||
promisify,
|
||||
middlewareSeries,
|
||||
sanitizeComponent,
|
||||
resolveRouteComponents,
|
||||
getMatchedComponents,
|
||||
getMatchedComponentsInstances,
|
||||
flatMapComponents,
|
||||
setContext,
|
||||
getLocation,
|
||||
compile,
|
||||
getQueryDiff,
|
||||
globalHandleError,
|
||||
isSamePath,
|
||||
urlJoin
|
||||
} from './utils.js'
|
||||
import { createApp, NuxtError } from './index.js'
|
||||
import fetchMixin from './mixins/fetch.client'
|
||||
import NuxtLink from './components/nuxt-link.client.js' // should be included after ./index.js
|
||||
|
||||
// Fetch mixin
|
||||
if (!Vue.__nuxt__fetch__mixin__) {
|
||||
Vue.mixin(fetchMixin)
|
||||
Vue.__nuxt__fetch__mixin__ = true
|
||||
}
|
||||
|
||||
// Component: <NuxtLink>
|
||||
Vue.component(NuxtLink.name, NuxtLink)
|
||||
Vue.component('NLink', NuxtLink)
|
||||
|
||||
if (!global.fetch) { global.fetch = fetch }
|
||||
|
||||
// Global shared references
|
||||
let _lastPaths = []
|
||||
let app
|
||||
let router
|
||||
let store
|
||||
|
||||
// Try to rehydrate SSR data from window
|
||||
const NUXT = window.__NUXT__ || {}
|
||||
|
||||
const $config = nuxt.publicRuntimeConfig || {}
|
||||
if ($config._app) {
|
||||
__webpack_public_path__ = urlJoin($config._app.cdnURL, $config._app.assetsPath)
|
||||
}
|
||||
|
||||
Object.assign(Vue.config, {"silent":false,"performance":true})
|
||||
|
||||
const logs = NUXT.logs || []
|
||||
if (logs.length > 0) {
|
||||
const ssrLogStyle = 'background: #2E495E;border-radius: 0.5em;color: white;font-weight: bold;padding: 2px 0.5em;'
|
||||
console.group && console.group ('%cNuxt SSR', ssrLogStyle)
|
||||
logs.forEach(logObj => (console[logObj.type] || console.log)(...logObj.args))
|
||||
delete NUXT.logs
|
||||
console.groupEnd && console.groupEnd()
|
||||
}
|
||||
|
||||
// Setup global Vue error handler
|
||||
if (!Vue.config.$nuxt) {
|
||||
const defaultErrorHandler = Vue.config.errorHandler
|
||||
Vue.config.errorHandler = async (err, vm, info, ...rest) => {
|
||||
// Call other handler if exist
|
||||
let handled = null
|
||||
if (typeof defaultErrorHandler === 'function') {
|
||||
handled = defaultErrorHandler(err, vm, info, ...rest)
|
||||
}
|
||||
if (handled === true) {
|
||||
return handled
|
||||
}
|
||||
|
||||
if (vm && vm.$root) {
|
||||
const nuxtApp = Object.keys(Vue.config.$nuxt)
|
||||
.find(nuxtInstance => vm.$root[nuxtInstance])
|
||||
|
||||
// Show Nuxt Error Page
|
||||
if (nuxtApp && vm.$root[nuxtApp].error && info !== 'render function') {
|
||||
const currentApp = vm.$root[nuxtApp]
|
||||
|
||||
// Load error layout
|
||||
let layout = (NuxtError.options || NuxtError).layout
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(currentApp.context)
|
||||
}
|
||||
if (layout) {
|
||||
await currentApp.loadLayout(layout).catch(() => {})
|
||||
}
|
||||
currentApp.setLayout(layout)
|
||||
|
||||
currentApp.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof defaultErrorHandler === 'function') {
|
||||
return handled
|
||||
}
|
||||
|
||||
// Log to console
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
console.error(err)
|
||||
} else {
|
||||
console.error(err.message || err)
|
||||
}
|
||||
}
|
||||
Vue.config.$nuxt = {}
|
||||
}
|
||||
Vue.config.$nuxt.$nuxt = true
|
||||
|
||||
const errorHandler = Vue.config.errorHandler || console.error
|
||||
|
||||
// Create and mount App
|
||||
createApp(null, nuxt.publicRuntimeConfig).then(mountApp).catch(errorHandler)
|
||||
|
||||
function componentOption (component, key, ...args) {
|
||||
if (!component || !component.options || !component.options[key]) {
|
||||
return {}
|
||||
}
|
||||
const option = component.options[key]
|
||||
if (typeof option === 'function') {
|
||||
return option(...args)
|
||||
}
|
||||
return option
|
||||
}
|
||||
|
||||
function mapTransitions (toComponents, to, from) {
|
||||
const componentTransitions = (component) => {
|
||||
const transition = componentOption(component, 'transition', to, from) || {}
|
||||
return (typeof transition === 'string' ? { name: transition } : transition)
|
||||
}
|
||||
|
||||
const fromComponents = from ? getMatchedComponents(from) : []
|
||||
const maxDepth = Math.max(toComponents.length, fromComponents.length)
|
||||
|
||||
const mergedTransitions = []
|
||||
for (let i=0; i<maxDepth; i++) {
|
||||
// Clone original objects to prevent overrides
|
||||
const toTransitions = Object.assign({}, componentTransitions(toComponents[i]))
|
||||
const transitions = Object.assign({}, componentTransitions(fromComponents[i]))
|
||||
|
||||
// Combine transitions & prefer `leave` properties of "from" route
|
||||
Object.keys(toTransitions)
|
||||
.filter(key => typeof toTransitions[key] !== 'undefined' && !key.toLowerCase().includes('leave'))
|
||||
.forEach((key) => { transitions[key] = toTransitions[key] })
|
||||
|
||||
mergedTransitions.push(transitions)
|
||||
}
|
||||
return mergedTransitions
|
||||
}
|
||||
|
||||
async function loadAsyncComponents (to, from, next) {
|
||||
// Check if route changed (this._routeChanged), only if the page is not an error (for validate())
|
||||
this._routeChanged = Boolean(app.nuxt.err) || from.name !== to.name
|
||||
this._paramChanged = !this._routeChanged && from.path !== to.path
|
||||
this._queryChanged = !this._paramChanged && from.fullPath !== to.fullPath
|
||||
this._diffQuery = (this._queryChanged ? getQueryDiff(to.query, from.query) : [])
|
||||
|
||||
if ((this._routeChanged || this._paramChanged) && this.$loading.start && !this.$loading.manual) {
|
||||
this.$loading.start()
|
||||
}
|
||||
|
||||
try {
|
||||
if (this._queryChanged) {
|
||||
const Components = await resolveRouteComponents(
|
||||
to,
|
||||
(Component, instance) => ({ Component, instance })
|
||||
)
|
||||
// Add a marker on each component that it needs to refresh or not
|
||||
const startLoader = Components.some(({ Component, instance }) => {
|
||||
const watchQuery = Component.options.watchQuery
|
||||
if (watchQuery === true) {
|
||||
return true
|
||||
}
|
||||
if (Array.isArray(watchQuery)) {
|
||||
return watchQuery.some(key => this._diffQuery[key])
|
||||
}
|
||||
if (typeof watchQuery === 'function') {
|
||||
return watchQuery.apply(instance, [to.query, from.query])
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
if (startLoader && this.$loading.start && !this.$loading.manual) {
|
||||
this.$loading.start()
|
||||
}
|
||||
}
|
||||
// Call next()
|
||||
next()
|
||||
} catch (error) {
|
||||
const err = error || {}
|
||||
const statusCode = err.statusCode || err.status || (err.response && err.response.status) || 500
|
||||
const message = err.message || ''
|
||||
|
||||
// Handle chunk loading errors
|
||||
// This may be due to a new deployment or a network problem
|
||||
if (/^Loading( CSS)? chunk (\d)+ failed\./.test(message)) {
|
||||
window.location.reload(true /* skip cache */)
|
||||
return // prevent error page blinking for user
|
||||
}
|
||||
|
||||
this.error({ statusCode, message })
|
||||
this.$nuxt.$emit('routeChanged', to, from, err)
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
function applySSRData (Component, ssrData) {
|
||||
if (NUXT.serverRendered && ssrData) {
|
||||
applyAsyncData(Component, ssrData)
|
||||
}
|
||||
|
||||
Component._Ctor = Component
|
||||
return Component
|
||||
}
|
||||
|
||||
// Get matched components
|
||||
function resolveComponents (route) {
|
||||
return flatMapComponents(route, async (Component, _, match, key, index) => {
|
||||
// If component is not resolved yet, resolve it
|
||||
if (typeof Component === 'function' && !Component.options) {
|
||||
Component = await Component()
|
||||
}
|
||||
// Sanitize it and save it
|
||||
const _Component = applySSRData(sanitizeComponent(Component), NUXT.data ? NUXT.data[index] : null)
|
||||
match.components[key] = _Component
|
||||
return _Component
|
||||
})
|
||||
}
|
||||
|
||||
function callMiddleware (Components, context, layout) {
|
||||
let midd = ["i18n"]
|
||||
let unknownMiddleware = false
|
||||
|
||||
// If layout is undefined, only call global middleware
|
||||
if (typeof layout !== 'undefined') {
|
||||
midd = [] // Exclude global middleware if layout defined (already called before)
|
||||
layout = sanitizeComponent(layout)
|
||||
if (layout.options.middleware) {
|
||||
midd = midd.concat(layout.options.middleware)
|
||||
}
|
||||
Components.forEach((Component) => {
|
||||
if (Component.options.middleware) {
|
||||
midd = midd.concat(Component.options.middleware)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
midd = midd.map((name) => {
|
||||
if (typeof name === 'function') {
|
||||
return name
|
||||
}
|
||||
if (typeof middleware[name] !== 'function') {
|
||||
unknownMiddleware = true
|
||||
this.error({ statusCode: 500, message: 'Unknown middleware ' + name })
|
||||
}
|
||||
return middleware[name]
|
||||
})
|
||||
|
||||
if (unknownMiddleware) {
|
||||
return
|
||||
}
|
||||
return middlewareSeries(midd, context)
|
||||
}
|
||||
|
||||
async function render (to, from, next) {
|
||||
if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) {
|
||||
return next()
|
||||
}
|
||||
// Handle first render on SPA mode
|
||||
let spaFallback = false
|
||||
if (to === from) {
|
||||
_lastPaths = []
|
||||
spaFallback = true
|
||||
} else {
|
||||
const fromMatches = []
|
||||
_lastPaths = getMatchedComponents(from, fromMatches).map((Component, i) => {
|
||||
return compile(from.matched[fromMatches[i]].path)(from.params)
|
||||
})
|
||||
}
|
||||
|
||||
// nextCalled is true when redirected
|
||||
let nextCalled = false
|
||||
const _next = (path) => {
|
||||
if (from.path === path.path && this.$loading.finish) {
|
||||
this.$loading.finish()
|
||||
}
|
||||
|
||||
if (from.path !== path.path && this.$loading.pause) {
|
||||
this.$loading.pause()
|
||||
}
|
||||
|
||||
if (nextCalled) {
|
||||
return
|
||||
}
|
||||
|
||||
nextCalled = true
|
||||
next(path)
|
||||
}
|
||||
|
||||
// Update context
|
||||
await setContext(app, {
|
||||
route: to,
|
||||
from,
|
||||
next: _next.bind(this)
|
||||
})
|
||||
this._dateLastError = app.nuxt.dateErr
|
||||
this._hadError = Boolean(app.nuxt.err)
|
||||
|
||||
// Get route's matched components
|
||||
const matches = []
|
||||
const Components = getMatchedComponents(to, matches)
|
||||
|
||||
// If no Components matched, generate 404
|
||||
if (!Components.length) {
|
||||
// Default layout
|
||||
await callMiddleware.call(this, Components, app.context)
|
||||
if (nextCalled) {
|
||||
return
|
||||
}
|
||||
|
||||
// Load layout for error page
|
||||
const errorLayout = (NuxtError.options || NuxtError).layout
|
||||
const layout = await this.loadLayout(
|
||||
typeof errorLayout === 'function'
|
||||
? errorLayout.call(NuxtError, app.context)
|
||||
: errorLayout
|
||||
)
|
||||
|
||||
await callMiddleware.call(this, Components, app.context, layout)
|
||||
if (nextCalled) {
|
||||
return
|
||||
}
|
||||
|
||||
// Show error page
|
||||
app.context.error({ statusCode: 404, message: 'This page could not be found' })
|
||||
return next()
|
||||
}
|
||||
|
||||
// Update ._data and other properties if hot reloaded
|
||||
Components.forEach((Component) => {
|
||||
if (Component._Ctor && Component._Ctor.options) {
|
||||
Component.options.asyncData = Component._Ctor.options.asyncData
|
||||
Component.options.fetch = Component._Ctor.options.fetch
|
||||
}
|
||||
})
|
||||
|
||||
// Apply transitions
|
||||
this.setTransitions(mapTransitions(Components, to, from))
|
||||
|
||||
try {
|
||||
// Call middleware
|
||||
await callMiddleware.call(this, Components, app.context)
|
||||
if (nextCalled) {
|
||||
return
|
||||
}
|
||||
if (app.context._errored) {
|
||||
return next()
|
||||
}
|
||||
|
||||
// Set layout
|
||||
let layout = Components[0].options.layout
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(app.context)
|
||||
}
|
||||
layout = await this.loadLayout(layout)
|
||||
|
||||
// Call middleware for layout
|
||||
await callMiddleware.call(this, Components, app.context, layout)
|
||||
if (nextCalled) {
|
||||
return
|
||||
}
|
||||
if (app.context._errored) {
|
||||
return next()
|
||||
}
|
||||
|
||||
// Call .validate()
|
||||
let isValid = true
|
||||
try {
|
||||
for (const Component of Components) {
|
||||
if (typeof Component.options.validate !== 'function') {
|
||||
continue
|
||||
}
|
||||
|
||||
isValid = await Component.options.validate(app.context)
|
||||
|
||||
if (!isValid) {
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (validationError) {
|
||||
// ...If .validate() threw an error
|
||||
this.error({
|
||||
statusCode: validationError.statusCode || '500',
|
||||
message: validationError.message
|
||||
})
|
||||
return next()
|
||||
}
|
||||
|
||||
// ...If .validate() returned false
|
||||
if (!isValid) {
|
||||
this.error({ statusCode: 404, message: 'This page could not be found' })
|
||||
return next()
|
||||
}
|
||||
|
||||
let instances
|
||||
// Call asyncData & fetch hooks on components matched by the route.
|
||||
await Promise.all(Components.map(async (Component, i) => {
|
||||
// Check if only children route changed
|
||||
Component._path = compile(to.matched[matches[i]].path)(to.params)
|
||||
Component._dataRefresh = false
|
||||
const childPathChanged = Component._path !== _lastPaths[i]
|
||||
// Refresh component (call asyncData & fetch) when:
|
||||
// Route path changed part includes current component
|
||||
// Or route param changed part includes current component and watchParam is not `false`
|
||||
// Or route query is changed and watchQuery returns `true`
|
||||
if (this._routeChanged && childPathChanged) {
|
||||
Component._dataRefresh = true
|
||||
} else if (this._paramChanged && childPathChanged) {
|
||||
const watchParam = Component.options.watchParam
|
||||
Component._dataRefresh = watchParam !== false
|
||||
} else if (this._queryChanged) {
|
||||
const watchQuery = Component.options.watchQuery
|
||||
if (watchQuery === true) {
|
||||
Component._dataRefresh = true
|
||||
} else if (Array.isArray(watchQuery)) {
|
||||
Component._dataRefresh = watchQuery.some(key => this._diffQuery[key])
|
||||
} else if (typeof watchQuery === 'function') {
|
||||
if (!instances) {
|
||||
instances = getMatchedComponentsInstances(to)
|
||||
}
|
||||
Component._dataRefresh = watchQuery.apply(instances[i], [to.query, from.query])
|
||||
}
|
||||
}
|
||||
if (!this._hadError && this._isMounted && !Component._dataRefresh) {
|
||||
return
|
||||
}
|
||||
|
||||
const promises = []
|
||||
|
||||
const hasAsyncData = (
|
||||
Component.options.asyncData &&
|
||||
typeof Component.options.asyncData === 'function'
|
||||
)
|
||||
|
||||
const hasFetch = Boolean(Component.options.fetch) && Component.options.fetch.length
|
||||
|
||||
const loadingIncrease = (hasAsyncData && hasFetch) ? 30 : 45
|
||||
|
||||
// Call asyncData(context)
|
||||
if (hasAsyncData) {
|
||||
const promise = promisify(Component.options.asyncData, app.context)
|
||||
|
||||
promise.then((asyncDataResult) => {
|
||||
applyAsyncData(Component, asyncDataResult)
|
||||
|
||||
if (this.$loading.increase) {
|
||||
this.$loading.increase(loadingIncrease)
|
||||
}
|
||||
})
|
||||
promises.push(promise)
|
||||
}
|
||||
|
||||
// Check disabled page loading
|
||||
this.$loading.manual = Component.options.loading === false
|
||||
|
||||
// Call fetch(context)
|
||||
if (hasFetch) {
|
||||
let p = Component.options.fetch(app.context)
|
||||
if (!p || (!(p instanceof Promise) && (typeof p.then !== 'function'))) {
|
||||
p = Promise.resolve(p)
|
||||
}
|
||||
p.then((fetchResult) => {
|
||||
if (this.$loading.increase) {
|
||||
this.$loading.increase(loadingIncrease)
|
||||
}
|
||||
})
|
||||
promises.push(p)
|
||||
}
|
||||
|
||||
return Promise.all(promises)
|
||||
}))
|
||||
|
||||
// If not redirected
|
||||
if (!nextCalled) {
|
||||
if (this.$loading.finish && !this.$loading.manual) {
|
||||
this.$loading.finish()
|
||||
}
|
||||
|
||||
next()
|
||||
}
|
||||
} catch (err) {
|
||||
const error = err || {}
|
||||
if (error.message === 'ERR_REDIRECT') {
|
||||
return this.$nuxt.$emit('routeChanged', to, from, error)
|
||||
}
|
||||
_lastPaths = []
|
||||
|
||||
globalHandleError(error)
|
||||
|
||||
// Load error layout
|
||||
let layout = (NuxtError.options || NuxtError).layout
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(app.context)
|
||||
}
|
||||
await this.loadLayout(layout)
|
||||
|
||||
this.error(error)
|
||||
this.$nuxt.$emit('routeChanged', to, from, error)
|
||||
next()
|
||||
}
|
||||
}
|
||||
|
||||
// Fix components format in matched, it's due to code-splitting of vue-router
|
||||
function normalizeComponents (to, ___) {
|
||||
flatMapComponents(to, (Component, _, match, key) => {
|
||||
if (typeof Component === 'object' && !Component.options) {
|
||||
// Updated via vue-router resolveAsyncComponents()
|
||||
Component = Vue.extend(Component)
|
||||
Component._Ctor = Component
|
||||
match.components[key] = Component
|
||||
}
|
||||
return Component
|
||||
})
|
||||
}
|
||||
|
||||
function setLayoutForNextPage (to) {
|
||||
// Set layout
|
||||
let hasError = Boolean(this.$options.nuxt.err)
|
||||
if (this._hadError && this._dateLastError === this.$options.nuxt.dateErr) {
|
||||
hasError = false
|
||||
}
|
||||
let layout = hasError
|
||||
? (NuxtError.options || NuxtError).layout
|
||||
: to.matched[0].components.default.options.layout
|
||||
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(app.context)
|
||||
}
|
||||
|
||||
this.setLayout(layout)
|
||||
}
|
||||
|
||||
function checkForErrors (app) {
|
||||
// Hide error component if no error
|
||||
if (app._hadError && app._dateLastError === app.$options.nuxt.dateErr) {
|
||||
app.error()
|
||||
}
|
||||
}
|
||||
|
||||
// When navigating on a different route but the same component is used, Vue.js
|
||||
// Will not update the instance data, so we have to update $data ourselves
|
||||
function fixPrepatch (to, ___) {
|
||||
if (this._routeChanged === false && this._paramChanged === false && this._queryChanged === false) {
|
||||
return
|
||||
}
|
||||
|
||||
const instances = getMatchedComponentsInstances(to)
|
||||
const Components = getMatchedComponents(to)
|
||||
|
||||
let triggerScroll = false
|
||||
|
||||
Vue.nextTick(() => {
|
||||
instances.forEach((instance, i) => {
|
||||
if (!instance || instance._isDestroyed) {
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
instance.constructor._dataRefresh &&
|
||||
Components[i] === instance.constructor &&
|
||||
instance.$vnode.data.keepAlive !== true &&
|
||||
typeof instance.constructor.options.data === 'function'
|
||||
) {
|
||||
const newData = instance.constructor.options.data.call(instance)
|
||||
for (const key in newData) {
|
||||
Vue.set(instance.$data, key, newData[key])
|
||||
}
|
||||
|
||||
triggerScroll = true
|
||||
}
|
||||
})
|
||||
|
||||
if (triggerScroll) {
|
||||
// Ensure to trigger scroll event after calling scrollBehavior
|
||||
window.$nuxt.$nextTick(() => {
|
||||
window.$nuxt.$emit('triggerScroll')
|
||||
})
|
||||
}
|
||||
|
||||
checkForErrors(this)
|
||||
|
||||
// Hot reloading
|
||||
setTimeout(() => hotReloadAPI(this), 100)
|
||||
})
|
||||
}
|
||||
|
||||
function nuxtReady (_app) {
|
||||
window.onNuxtReadyCbs.forEach((cb) => {
|
||||
if (typeof cb === 'function') {
|
||||
cb(_app)
|
||||
}
|
||||
})
|
||||
// Special JSDOM
|
||||
if (typeof window._onNuxtLoaded === 'function') {
|
||||
window._onNuxtLoaded(_app)
|
||||
}
|
||||
// Add router hooks
|
||||
router.afterEach((to, from) => {
|
||||
// Wait for fixPrepatch + $data updates
|
||||
Vue.nextTick(() => _app.$nuxt.$emit('routeChanged', to, from))
|
||||
})
|
||||
}
|
||||
|
||||
const noopData = () => { return {} }
|
||||
const noopFetch = () => {}
|
||||
|
||||
// Special hot reload with asyncData(context)
|
||||
function getNuxtChildComponents ($parent, $components = []) {
|
||||
$parent.$children.forEach(($child) => {
|
||||
if ($child.$vnode && $child.$vnode.data.nuxtChild && !$components.find(c =>(c.$options.__file === $child.$options.__file))) {
|
||||
$components.push($child)
|
||||
}
|
||||
if ($child.$children && $child.$children.length) {
|
||||
getNuxtChildComponents($child, $components)
|
||||
}
|
||||
})
|
||||
|
||||
return $components
|
||||
}
|
||||
|
||||
function hotReloadAPI(_app) {
|
||||
if (!module.hot) return
|
||||
|
||||
let $components = getNuxtChildComponents(_app.$nuxt, [])
|
||||
|
||||
$components.forEach(addHotReload.bind(_app))
|
||||
}
|
||||
|
||||
function addHotReload ($component, depth) {
|
||||
if ($component.$vnode.data._hasHotReload) return
|
||||
$component.$vnode.data._hasHotReload = true
|
||||
|
||||
var _forceUpdate = $component.$forceUpdate.bind($component.$parent)
|
||||
|
||||
$component.$vnode.context.$forceUpdate = async () => {
|
||||
let Components = getMatchedComponents(router.currentRoute)
|
||||
let Component = Components[depth]
|
||||
if (!Component) {
|
||||
return _forceUpdate()
|
||||
}
|
||||
if (typeof Component === 'object' && !Component.options) {
|
||||
// Updated via vue-router resolveAsyncComponents()
|
||||
Component = Vue.extend(Component)
|
||||
Component._Ctor = Component
|
||||
}
|
||||
this.error()
|
||||
let promises = []
|
||||
const next = function (path) {
|
||||
this.$loading.finish && this.$loading.finish()
|
||||
router.push(path)
|
||||
}
|
||||
await setContext(app, {
|
||||
route: router.currentRoute,
|
||||
isHMR: true,
|
||||
next: next.bind(this)
|
||||
})
|
||||
const context = app.context
|
||||
|
||||
if (this.$loading.start && !this.$loading.manual) {
|
||||
this.$loading.start()
|
||||
}
|
||||
|
||||
callMiddleware.call(this, Components, context)
|
||||
.then(() => {
|
||||
// If layout changed
|
||||
if (depth !== 0) {
|
||||
return
|
||||
}
|
||||
|
||||
let layout = Component.options.layout || 'default'
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(context)
|
||||
}
|
||||
if (this.layoutName === layout) {
|
||||
return
|
||||
}
|
||||
let promise = this.loadLayout(layout)
|
||||
promise.then(() => {
|
||||
this.setLayout(layout)
|
||||
Vue.nextTick(() => hotReloadAPI(this))
|
||||
})
|
||||
return promise
|
||||
})
|
||||
|
||||
.then(() => {
|
||||
return callMiddleware.call(this, Components, context, this.layout)
|
||||
})
|
||||
|
||||
.then(() => {
|
||||
// Call asyncData(context)
|
||||
let pAsyncData = promisify(Component.options.asyncData || noopData, context)
|
||||
pAsyncData.then((asyncDataResult) => {
|
||||
applyAsyncData(Component, asyncDataResult)
|
||||
this.$loading.increase && this.$loading.increase(30)
|
||||
})
|
||||
promises.push(pAsyncData)
|
||||
|
||||
// Call fetch()
|
||||
Component.options.fetch = Component.options.fetch || noopFetch
|
||||
let pFetch = Component.options.fetch.length && Component.options.fetch(context)
|
||||
if (!pFetch || (!(pFetch instanceof Promise) && (typeof pFetch.then !== 'function'))) { pFetch = Promise.resolve(pFetch) }
|
||||
pFetch.then(() => this.$loading.increase && this.$loading.increase(30))
|
||||
promises.push(pFetch)
|
||||
|
||||
return Promise.all(promises)
|
||||
})
|
||||
.then(() => {
|
||||
this.$loading.finish && this.$loading.finish()
|
||||
_forceUpdate()
|
||||
setTimeout(() => hotReloadAPI(this), 100)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function mountApp (__app) {
|
||||
// Set global variables
|
||||
app = __app.app
|
||||
router = __app.router
|
||||
store = __app.store
|
||||
|
||||
// Create Vue instance
|
||||
const _app = new Vue(app)
|
||||
|
||||
// Mounts Vue app to DOM element
|
||||
const mount = () => {
|
||||
_app.$mount('#app')
|
||||
|
||||
// Add afterEach router hooks
|
||||
router.afterEach(normalizeComponents)
|
||||
|
||||
router.afterEach(setLayoutForNextPage.bind(_app))
|
||||
|
||||
router.afterEach(fixPrepatch.bind(_app))
|
||||
|
||||
// Listen for first Vue update
|
||||
Vue.nextTick(() => {
|
||||
// Call window.{{globals.readyCallback}} callbacks
|
||||
nuxtReady(_app)
|
||||
|
||||
// Enable hot reloading
|
||||
hotReloadAPI(_app)
|
||||
})
|
||||
}
|
||||
|
||||
// Resolve route components
|
||||
const Components = await Promise.all(resolveComponents(app.context.route))
|
||||
|
||||
// Enable transitions
|
||||
_app.setTransitions = _app.$options.nuxt.setTransitions.bind(_app)
|
||||
if (Components.length) {
|
||||
_app.setTransitions(mapTransitions(Components, router.currentRoute))
|
||||
_lastPaths = router.currentRoute.matched.map(route => compile(route.path)(router.currentRoute.params))
|
||||
}
|
||||
|
||||
// Initialize error handler
|
||||
_app.$loading = {} // To avoid error while _app.$nuxt does not exist
|
||||
if (NUXT.error) {
|
||||
_app.error(NUXT.error)
|
||||
}
|
||||
|
||||
// Add beforeEach router hooks
|
||||
router.beforeEach(loadAsyncComponents.bind(_app))
|
||||
router.beforeEach(render.bind(_app))
|
||||
|
||||
// Fix in static: remove trailing slash to force hydration
|
||||
// Full static, if server-rendered: hydrate, to allow custom redirect to generated page
|
||||
|
||||
// Fix in static: remove trailing slash to force hydration
|
||||
if (NUXT.serverRendered && isSamePath(NUXT.routePath, _app.context.route.path)) {
|
||||
return mount()
|
||||
}
|
||||
|
||||
// First render on client-side
|
||||
const clientFirstMount = () => {
|
||||
normalizeComponents(router.currentRoute, router.currentRoute)
|
||||
setLayoutForNextPage.call(_app, router.currentRoute)
|
||||
checkForErrors(_app)
|
||||
// Don't call fixPrepatch.call(_app, router.currentRoute, router.currentRoute) since it's first render
|
||||
mount()
|
||||
}
|
||||
|
||||
// fix: force next tick to avoid having same timestamp when an error happen on spa fallback
|
||||
await new Promise(resolve => setTimeout(resolve, 0))
|
||||
render.call(_app, router.currentRoute, router.currentRoute, (path) => {
|
||||
// If not redirected
|
||||
if (!path) {
|
||||
clientFirstMount()
|
||||
return
|
||||
}
|
||||
|
||||
// Add a one-time afterEach hook to
|
||||
// mount the app wait for redirect and route gets resolved
|
||||
const unregisterHook = router.afterEach((to, from) => {
|
||||
unregisterHook()
|
||||
clientFirstMount()
|
||||
})
|
||||
|
||||
// Push the path and let route to be resolved
|
||||
router.push(path, undefined, (err) => {
|
||||
if (err) {
|
||||
errorHandler(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
<template>
|
||||
<transition appear>
|
||||
<div v-if="building" class="nuxt__build_indicator" :style="indicatorStyle">
|
||||
<svg viewBox="0 0 96 72" version="1" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path d="M6 66h23l1-3 21-37L40 6 6 66zM79 66h11L62 17l-5 9 22 37v3zM54 31L35 66h38z" />
|
||||
<path d="M29 69v-1-2H6L40 6l11 20 3-6L44 3s-2-3-4-3-3 1-5 3L1 63c0 1-2 3 0 6 0 1 2 2 5 2h28c-3 0-4-1-5-2z" fill="#00C58E" />
|
||||
<path d="M95 63L67 14c0-1-2-3-5-3-1 0-3 0-4 3l-4 6 3 6 5-9 28 49H79a5 5 0 0 1 0 3c-2 2-5 2-5 2h16c1 0 4 0 5-2 1-1 2-3 0-6z" fill="#00C58E" />
|
||||
<path d="M79 69v-1-2-3L57 26l-3-6-3 6-21 37-1 3a5 5 0 0 0 0 3c1 1 2 2 5 2h40s3 0 5-2zM54 31l19 35H35l19-35z" fill="#FFF" fill-rule="nonzero" />
|
||||
</g>
|
||||
</svg>
|
||||
{{ animatedProgress }}%
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NuxtBuildIndicator',
|
||||
data () {
|
||||
return {
|
||||
building: false,
|
||||
progress: 0,
|
||||
animatedProgress: 0,
|
||||
reconnectAttempts: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
options: () => ({"position":"bottom-right","backgroundColor":"#2E495E","color":"#00C48D"}),
|
||||
indicatorStyle () {
|
||||
const [d1, d2] = this.options.position.split('-')
|
||||
return {
|
||||
[d1]: '20px',
|
||||
[d2]: '20px',
|
||||
'background-color': this.options.backgroundColor,
|
||||
color: this.options.color
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
progress (val, oldVal) {
|
||||
// Average progress may decrease but ignore it!
|
||||
if (val < oldVal) {
|
||||
return
|
||||
}
|
||||
// Cancel old animation
|
||||
clearInterval(this._progressAnimation)
|
||||
// Jump to edge immediately
|
||||
if (val < 10 || val > 90) {
|
||||
this.animatedProgress = val
|
||||
return
|
||||
}
|
||||
// Animate to value
|
||||
this._progressAnimation = setInterval(() => {
|
||||
const diff = this.progress - this.animatedProgress
|
||||
if (diff > 0) {
|
||||
this.animatedProgress++
|
||||
} else {
|
||||
clearInterval(this._progressAnimation)
|
||||
}
|
||||
}, 50)
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (EventSource === undefined) {
|
||||
return // Unsupported
|
||||
}
|
||||
this.sseConnect()
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.sseClose()
|
||||
clearInterval(this._progressAnimation)
|
||||
},
|
||||
methods: {
|
||||
sseConnect () {
|
||||
if (this._connecting) {
|
||||
return
|
||||
}
|
||||
this._connecting = true
|
||||
this.sse = new EventSource('/_loading/sse')
|
||||
this.sse.addEventListener('message', event => this.onSseMessage(event))
|
||||
},
|
||||
onSseMessage (message) {
|
||||
const data = JSON.parse(message.data)
|
||||
if (!data.states) {
|
||||
return
|
||||
}
|
||||
|
||||
this.progress = Math.round(data.states.reduce((p, s) => p + s.progress, 0) / data.states.length)
|
||||
|
||||
if (!data.allDone) {
|
||||
this.building = true
|
||||
} else {
|
||||
this.$nextTick(() => {
|
||||
this.building = false
|
||||
this.animatedProgress = 0
|
||||
this.progress = 0
|
||||
clearInterval(this._progressAnimation)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
sseClose () {
|
||||
if (this.sse) {
|
||||
this.sse.close()
|
||||
delete this.sse
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.nuxt__build_indicator {
|
||||
box-sizing: border-box;
|
||||
position: fixed;
|
||||
font-family: monospace;
|
||||
padding: 5px 10px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 1px 1px 2px 0px rgba(0,0,0,0.2);
|
||||
width: 88px;
|
||||
z-index: 2147483647;
|
||||
font-size: 16px;
|
||||
line-height: 1.2rem;
|
||||
}
|
||||
.v-enter-active, .v-leave-active {
|
||||
transition-delay: 0.2s;
|
||||
transition-property: all;
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
.v-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
svg {
|
||||
display: inline-block;
|
||||
vertical-align: baseline;
|
||||
width: 1.1em;
|
||||
height: 0.825em;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
|
||||
export default {
|
||||
name: 'NuxtChild',
|
||||
functional: true,
|
||||
props: {
|
||||
nuxtChildKey: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
keepAlive: Boolean,
|
||||
keepAliveProps: {
|
||||
type: Object,
|
||||
default: undefined
|
||||
}
|
||||
},
|
||||
render (_, { parent, data, props }) {
|
||||
const h = parent.$createElement
|
||||
|
||||
data.nuxtChild = true
|
||||
const _parent = parent
|
||||
const transitions = parent.$nuxt.nuxt.transitions
|
||||
const defaultTransition = parent.$nuxt.nuxt.defaultTransition
|
||||
|
||||
let depth = 0
|
||||
while (parent) {
|
||||
if (parent.$vnode && parent.$vnode.data.nuxtChild) {
|
||||
depth++
|
||||
}
|
||||
parent = parent.$parent
|
||||
}
|
||||
data.nuxtChildDepth = depth
|
||||
const transition = transitions[depth] || defaultTransition
|
||||
const transitionProps = {}
|
||||
transitionsKeys.forEach((key) => {
|
||||
if (typeof transition[key] !== 'undefined') {
|
||||
transitionProps[key] = transition[key]
|
||||
}
|
||||
})
|
||||
|
||||
const listeners = {}
|
||||
listenersKeys.forEach((key) => {
|
||||
if (typeof transition[key] === 'function') {
|
||||
listeners[key] = transition[key].bind(_parent)
|
||||
}
|
||||
})
|
||||
if (process.client) {
|
||||
// Add triggerScroll event on beforeEnter (fix #1376)
|
||||
const beforeEnter = listeners.beforeEnter
|
||||
listeners.beforeEnter = (el) => {
|
||||
// Ensure to trigger scroll event after calling scrollBehavior
|
||||
window.$nuxt.$nextTick(() => {
|
||||
window.$nuxt.$emit('triggerScroll')
|
||||
})
|
||||
if (beforeEnter) {
|
||||
return beforeEnter.call(_parent, el)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// make sure that leave is called asynchronous (fix #5703)
|
||||
if (transition.css === false) {
|
||||
const leave = listeners.leave
|
||||
|
||||
// only add leave listener when user didnt provide one
|
||||
// or when it misses the done argument
|
||||
if (!leave || leave.length < 2) {
|
||||
listeners.leave = (el, done) => {
|
||||
if (leave) {
|
||||
leave.call(_parent, el)
|
||||
}
|
||||
|
||||
_parent.$nextTick(done)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let routerView = h('routerView', data)
|
||||
|
||||
if (props.keepAlive) {
|
||||
routerView = h('keep-alive', { props: props.keepAliveProps }, [routerView])
|
||||
}
|
||||
|
||||
return h('transition', {
|
||||
props: transitionProps,
|
||||
on: listeners
|
||||
}, [routerView])
|
||||
}
|
||||
}
|
||||
|
||||
const transitionsKeys = [
|
||||
'name',
|
||||
'mode',
|
||||
'appear',
|
||||
'css',
|
||||
'type',
|
||||
'duration',
|
||||
'enterClass',
|
||||
'leaveClass',
|
||||
'appearClass',
|
||||
'enterActiveClass',
|
||||
'enterActiveClass',
|
||||
'leaveActiveClass',
|
||||
'appearActiveClass',
|
||||
'enterToClass',
|
||||
'leaveToClass',
|
||||
'appearToClass'
|
||||
]
|
||||
|
||||
const listenersKeys = [
|
||||
'beforeEnter',
|
||||
'enter',
|
||||
'afterEnter',
|
||||
'enterCancelled',
|
||||
'beforeLeave',
|
||||
'leave',
|
||||
'afterLeave',
|
||||
'leaveCancelled',
|
||||
'beforeAppear',
|
||||
'appear',
|
||||
'afterAppear',
|
||||
'appearCancelled'
|
||||
]
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
<template>
|
||||
<div class="__nuxt-error-page">
|
||||
<div class="error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90" fill="#DBE1EC" viewBox="0 0 48 48">
|
||||
<path d="M22 30h4v4h-4zm0-16h4v12h-4zm1.99-10C12.94 4 4 12.95 4 24s8.94 20 19.99 20S44 35.05 44 24 35.04 4 23.99 4zM24 40c-8.84 0-16-7.16-16-16S15.16 8 24 8s16 7.16 16 16-7.16 16-16 16z" />
|
||||
</svg>
|
||||
|
||||
<div class="title">{{ message }}</div>
|
||||
<p v-if="statusCode === 404" class="description">
|
||||
<a v-if="typeof $route === 'undefined'" class="error-link" href="/"></a>
|
||||
<NuxtLink v-else class="error-link" to="/">Back to the home page</NuxtLink>
|
||||
</p>
|
||||
|
||||
<p class="description" v-else>An error occurred while rendering the page. Check developer tools console for details.</p>
|
||||
|
||||
<div class="logo">
|
||||
<a href="https://nuxtjs.org" target="_blank" rel="noopener">Nuxt</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'NuxtError',
|
||||
props: {
|
||||
error: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
statusCode () {
|
||||
return (this.error && this.error.statusCode) || 500
|
||||
},
|
||||
message () {
|
||||
return this.error.message || 'Error'
|
||||
}
|
||||
},
|
||||
head () {
|
||||
return {
|
||||
title: this.message,
|
||||
meta: [
|
||||
{
|
||||
name: 'viewport',
|
||||
content: 'width=device-width,initial-scale=1.0,minimum-scale=1.0'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.__nuxt-error-page {
|
||||
padding: 1rem;
|
||||
background: #F7F8FB;
|
||||
color: #47494E;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
font-family: sans-serif;
|
||||
font-weight: 100 !important;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.__nuxt-error-page .error {
|
||||
max-width: 450px;
|
||||
}
|
||||
.__nuxt-error-page .title {
|
||||
font-size: 1.5rem;
|
||||
margin-top: 15px;
|
||||
color: #47494E;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.__nuxt-error-page .description {
|
||||
color: #7F828B;
|
||||
line-height: 21px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.__nuxt-error-page a {
|
||||
color: #7F828B !important;
|
||||
text-decoration: none;
|
||||
}
|
||||
.__nuxt-error-page .logo {
|
||||
position: fixed;
|
||||
left: 12px;
|
||||
bottom: 12px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
import Vue from 'vue'
|
||||
|
||||
const requestIdleCallback = window.requestIdleCallback ||
|
||||
function (cb) {
|
||||
const start = Date.now()
|
||||
return setTimeout(function () {
|
||||
cb({
|
||||
didTimeout: false,
|
||||
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
|
||||
})
|
||||
}, 1)
|
||||
}
|
||||
|
||||
const cancelIdleCallback = window.cancelIdleCallback || function (id) {
|
||||
clearTimeout(id)
|
||||
}
|
||||
|
||||
const observer = window.IntersectionObserver && new window.IntersectionObserver((entries) => {
|
||||
entries.forEach(({ intersectionRatio, target: link }) => {
|
||||
if (intersectionRatio <= 0 || !link.__prefetch) {
|
||||
return
|
||||
}
|
||||
link.__prefetch()
|
||||
})
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'NuxtLink',
|
||||
extends: Vue.component('RouterLink'),
|
||||
props: {
|
||||
prefetch: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
noPrefetch: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (this.prefetch && !this.noPrefetch) {
|
||||
this.handleId = requestIdleCallback(this.observe, { timeout: 2e3 })
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
cancelIdleCallback(this.handleId)
|
||||
|
||||
if (this.__observed) {
|
||||
observer.unobserve(this.$el)
|
||||
delete this.$el.__prefetch
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
observe () {
|
||||
// If no IntersectionObserver, avoid prefetching
|
||||
if (!observer) {
|
||||
return
|
||||
}
|
||||
// Add to observer
|
||||
if (this.shouldPrefetch()) {
|
||||
this.$el.__prefetch = this.prefetchLink.bind(this)
|
||||
observer.observe(this.$el)
|
||||
this.__observed = true
|
||||
}
|
||||
},
|
||||
shouldPrefetch () {
|
||||
return this.getPrefetchComponents().length > 0
|
||||
},
|
||||
canPrefetch () {
|
||||
const conn = navigator.connection
|
||||
const hasBadConnection = this.$nuxt.isOffline || (conn && ((conn.effectiveType || '').includes('2g') || conn.saveData))
|
||||
|
||||
return !hasBadConnection
|
||||
},
|
||||
getPrefetchComponents () {
|
||||
const ref = this.$router.resolve(this.to, this.$route, this.append)
|
||||
const Components = ref.resolved.matched.map(r => r.components.default)
|
||||
|
||||
return Components.filter(Component => typeof Component === 'function' && !Component.options && !Component.__prefetched)
|
||||
},
|
||||
prefetchLink () {
|
||||
if (!this.canPrefetch()) {
|
||||
return
|
||||
}
|
||||
// Stop observing this link (in case of internet connection changes)
|
||||
observer.unobserve(this.$el)
|
||||
const Components = this.getPrefetchComponents()
|
||||
|
||||
for (const Component of Components) {
|
||||
const componentOrPromise = Component()
|
||||
if (componentOrPromise instanceof Promise) {
|
||||
componentOrPromise.catch(() => {})
|
||||
}
|
||||
Component.__prefetched = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import Vue from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'NuxtLink',
|
||||
extends: Vue.component('RouterLink'),
|
||||
props: {
|
||||
prefetch: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
noPrefetch: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
<script>
|
||||
export default {
|
||||
name: 'NuxtLoading',
|
||||
data () {
|
||||
return {
|
||||
percent: 0,
|
||||
show: false,
|
||||
canSucceed: true,
|
||||
reversed: false,
|
||||
skipTimerCount: 0,
|
||||
rtl: false,
|
||||
throttle: 200,
|
||||
duration: 3000,
|
||||
continuous: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
left () {
|
||||
if (!this.continuous && !this.rtl) {
|
||||
return false
|
||||
}
|
||||
return this.rtl
|
||||
? (this.reversed ? '0px' : 'auto')
|
||||
: (!this.reversed ? '0px' : 'auto')
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.clear()
|
||||
},
|
||||
methods: {
|
||||
clear () {
|
||||
clearInterval(this._timer)
|
||||
clearTimeout(this._throttle)
|
||||
this._timer = null
|
||||
},
|
||||
start () {
|
||||
this.clear()
|
||||
this.percent = 0
|
||||
this.reversed = false
|
||||
this.skipTimerCount = 0
|
||||
this.canSucceed = true
|
||||
|
||||
if (this.throttle) {
|
||||
this._throttle = setTimeout(() => this.startTimer(), this.throttle)
|
||||
} else {
|
||||
this.startTimer()
|
||||
}
|
||||
return this
|
||||
},
|
||||
set (num) {
|
||||
this.show = true
|
||||
this.canSucceed = true
|
||||
this.percent = Math.min(100, Math.max(0, Math.floor(num)))
|
||||
return this
|
||||
},
|
||||
get () {
|
||||
return this.percent
|
||||
},
|
||||
increase (num) {
|
||||
this.percent = Math.min(100, Math.floor(this.percent + num))
|
||||
return this
|
||||
},
|
||||
decrease (num) {
|
||||
this.percent = Math.max(0, Math.floor(this.percent - num))
|
||||
return this
|
||||
},
|
||||
pause () {
|
||||
clearInterval(this._timer)
|
||||
return this
|
||||
},
|
||||
resume () {
|
||||
this.startTimer()
|
||||
return this
|
||||
},
|
||||
finish () {
|
||||
this.percent = this.reversed ? 0 : 100
|
||||
this.hide()
|
||||
return this
|
||||
},
|
||||
hide () {
|
||||
this.clear()
|
||||
setTimeout(() => {
|
||||
this.show = false
|
||||
this.$nextTick(() => {
|
||||
this.percent = 0
|
||||
this.reversed = false
|
||||
})
|
||||
}, 500)
|
||||
return this
|
||||
},
|
||||
fail (error) {
|
||||
this.canSucceed = false
|
||||
return this
|
||||
},
|
||||
startTimer () {
|
||||
if (!this.show) {
|
||||
this.show = true
|
||||
}
|
||||
if (typeof this._cut === 'undefined') {
|
||||
this._cut = 10000 / Math.floor(this.duration)
|
||||
}
|
||||
|
||||
this._timer = setInterval(() => {
|
||||
/**
|
||||
* When reversing direction skip one timers
|
||||
* so 0, 100 are displayed for two iterations
|
||||
* also disable css width transitioning
|
||||
* which otherwise interferes and shows
|
||||
* a jojo effect
|
||||
*/
|
||||
if (this.skipTimerCount > 0) {
|
||||
this.skipTimerCount--
|
||||
return
|
||||
}
|
||||
|
||||
if (this.reversed) {
|
||||
this.decrease(this._cut)
|
||||
} else {
|
||||
this.increase(this._cut)
|
||||
}
|
||||
|
||||
if (this.continuous) {
|
||||
if (this.percent >= 100) {
|
||||
this.skipTimerCount = 1
|
||||
|
||||
this.reversed = !this.reversed
|
||||
} else if (this.percent <= 0) {
|
||||
this.skipTimerCount = 1
|
||||
|
||||
this.reversed = !this.reversed
|
||||
}
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
let el = h(false)
|
||||
if (this.show) {
|
||||
el = h('div', {
|
||||
staticClass: 'nuxt-progress',
|
||||
class: {
|
||||
'nuxt-progress-notransition': this.skipTimerCount > 0,
|
||||
'nuxt-progress-failed': !this.canSucceed
|
||||
},
|
||||
style: {
|
||||
width: this.percent + '%',
|
||||
left: this.left
|
||||
}
|
||||
})
|
||||
}
|
||||
return el
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
import Vue from 'vue'
|
||||
import { compile } from '../utils'
|
||||
|
||||
import NuxtError from '../../layouts/error.vue'
|
||||
|
||||
import NuxtChild from './nuxt-child'
|
||||
|
||||
export default {
|
||||
name: 'Nuxt',
|
||||
components: {
|
||||
NuxtChild,
|
||||
NuxtError
|
||||
},
|
||||
props: {
|
||||
nuxtChildKey: {
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
keepAlive: Boolean,
|
||||
keepAliveProps: {
|
||||
type: Object,
|
||||
default: undefined
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: 'default'
|
||||
}
|
||||
},
|
||||
errorCaptured (error) {
|
||||
// if we receive and error while showing the NuxtError component
|
||||
// capture the error and force an immediate update so we re-render
|
||||
// without the NuxtError component
|
||||
if (this.displayingNuxtError) {
|
||||
this.errorFromNuxtError = error
|
||||
this.$forceUpdate()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
routerViewKey () {
|
||||
// If nuxtChildKey prop is given or current route has children
|
||||
if (typeof this.nuxtChildKey !== 'undefined' || this.$route.matched.length > 1) {
|
||||
return this.nuxtChildKey || compile(this.$route.matched[0].path)(this.$route.params)
|
||||
}
|
||||
|
||||
const [matchedRoute] = this.$route.matched
|
||||
|
||||
if (!matchedRoute) {
|
||||
return this.$route.path
|
||||
}
|
||||
|
||||
const Component = matchedRoute.components.default
|
||||
|
||||
if (Component && Component.options) {
|
||||
const { options } = Component
|
||||
|
||||
if (options.key) {
|
||||
return (typeof options.key === 'function' ? options.key(this.$route) : options.key)
|
||||
}
|
||||
}
|
||||
|
||||
const strict = /\/$/.test(matchedRoute.path)
|
||||
return strict ? this.$route.path : this.$route.path.replace(/\/$/, '')
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
Vue.util.defineReactive(this, 'nuxt', this.$root.$options.nuxt)
|
||||
},
|
||||
render (h) {
|
||||
// if there is no error
|
||||
if (!this.nuxt.err) {
|
||||
// Directly return nuxt child
|
||||
return h('NuxtChild', {
|
||||
key: this.routerViewKey,
|
||||
props: this.$props
|
||||
})
|
||||
}
|
||||
|
||||
// if an error occurred within NuxtError show a simple
|
||||
// error message instead to prevent looping
|
||||
if (this.errorFromNuxtError) {
|
||||
this.$nextTick(() => (this.errorFromNuxtError = false))
|
||||
|
||||
return h('div', {}, [
|
||||
h('h2', 'An error occurred while showing the error page'),
|
||||
h('p', 'Unfortunately an error occurred and while showing the error page another error occurred'),
|
||||
h('p', `Error details: ${this.errorFromNuxtError.toString()}`),
|
||||
h('nuxt-link', { props: { to: '/' } }, 'Go back to home')
|
||||
])
|
||||
}
|
||||
|
||||
// track if we are showing the NuxtError component
|
||||
this.displayingNuxtError = true
|
||||
this.$nextTick(() => (this.displayingNuxtError = false))
|
||||
|
||||
return h(NuxtError, {
|
||||
props: {
|
||||
error: this.nuxt.err
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import cookieUniversal from 'cookie-universal'
|
||||
|
||||
export default ({ req, res }, inject) => {
|
||||
const options = {
|
||||
"alias": "cookies",
|
||||
"parseJSON": true
|
||||
}
|
||||
inject(options.alias, cookieUniversal(req, res, options.parseJSON))
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
// This file is intentionally left empty for noop aliases
|
||||
|
|
@ -0,0 +1,364 @@
|
|||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import Meta from 'vue-meta';
|
||||
import ClientOnly from 'vue-client-only';
|
||||
import NoSsr from 'vue-no-ssr';
|
||||
import { createRouter } from './router.js';
|
||||
import NuxtChild from './components/nuxt-child.js';
|
||||
import NuxtError from '../layouts/error.vue';
|
||||
import Nuxt from './components/nuxt.js';
|
||||
import App from './App.js';
|
||||
import { setContext, getLocation, getRouteData, normalizeError } from './utils';
|
||||
import { createStore } from './store.js';
|
||||
|
||||
/* Plugins */
|
||||
|
||||
import './portal-vue.js';
|
||||
import cookieUniversalNuxt from './cookie-universal-nuxt.js';
|
||||
import axios from './axios.js';
|
||||
import plugins from '../core/plugins.js';
|
||||
import pluginsLoader from '../core/plugins-loader.js';
|
||||
import axiosShell from '../plugins/axios';
|
||||
import '../plugins/tooltip';
|
||||
import '../plugins/vue-clipboard2';
|
||||
import '../plugins/v-select';
|
||||
import '../plugins/directives';
|
||||
import '../plugins/transitions';
|
||||
import '../plugins/vue-js-modal';
|
||||
import '../plugins/js-yaml';
|
||||
import '../plugins/resize';
|
||||
import '../plugins/shortkey';
|
||||
import '../plugins/i18n';
|
||||
import '../plugins/global-formatters';
|
||||
import '../plugins/trim-whitespace';
|
||||
import '../plugins/extend-router';
|
||||
|
||||
import consolePlugin from '../plugins/console';
|
||||
import intNumber from '../plugins/int-number';
|
||||
import nuxtClientInit from '../plugins/nuxt-client-init';
|
||||
import replaceAll from '../plugins/replaceall';
|
||||
import backButton from '../plugins/back-button';
|
||||
import plugin from '../plugins/plugin';
|
||||
import codeMirror from '../plugins/codemirror-loader';
|
||||
import '../plugins/formatters';
|
||||
import version from '../plugins/version';
|
||||
import steveCreateWorker from '../plugins/steve-create-worker';
|
||||
|
||||
// Component: <ClientOnly>
|
||||
Vue.component(ClientOnly.name, ClientOnly);
|
||||
|
||||
// TODO: Remove in Nuxt 3: <NoSsr>
|
||||
Vue.component(NoSsr.name, {
|
||||
...NoSsr,
|
||||
render(h, ctx) {
|
||||
if (process.client && !NoSsr._warned) {
|
||||
NoSsr._warned = true;
|
||||
|
||||
console.warn('<no-ssr> has been deprecated and will be removed in Nuxt 3, please use <client-only> instead');
|
||||
}
|
||||
|
||||
return NoSsr.render(h, ctx);
|
||||
}
|
||||
});
|
||||
|
||||
// Component: <NuxtChild>
|
||||
Vue.component(NuxtChild.name, NuxtChild);
|
||||
Vue.component('NChild', NuxtChild);
|
||||
|
||||
// Component NuxtLink is imported in server.js or client.js
|
||||
|
||||
// Component: <Nuxt>
|
||||
Vue.component(Nuxt.name, Nuxt);
|
||||
|
||||
Object.defineProperty(Vue.prototype, '$nuxt', {
|
||||
get() {
|
||||
const globalNuxt = this.$root.$options.$nuxt;
|
||||
|
||||
if (process.client && !globalNuxt && typeof window !== 'undefined') {
|
||||
return window.$nuxt;
|
||||
}
|
||||
|
||||
return globalNuxt;
|
||||
},
|
||||
configurable: true
|
||||
});
|
||||
|
||||
Vue.use(Meta, {
|
||||
keyName: 'head', attribute: 'data-n-head', ssrAttribute: 'data-n-head-ssr', tagIDKeyName: 'hid'
|
||||
});
|
||||
|
||||
const defaultTransition = {
|
||||
name: 'page', mode: 'out-in', appear: true, appearClass: 'appear', appearActiveClass: 'appear-active', appearToClass: 'appear-to'
|
||||
};
|
||||
|
||||
const originalRegisterModule = Vuex.Store.prototype.registerModule;
|
||||
|
||||
function registerModule(path, rawModule, options = {}) {
|
||||
const preserveState = process.client && (
|
||||
Array.isArray(path) ? !!path.reduce((namespacedState, path) => namespacedState && namespacedState[path], this.state) : path in this.state
|
||||
);
|
||||
|
||||
return originalRegisterModule.call(this, path, rawModule, { preserveState, ...options });
|
||||
}
|
||||
|
||||
async function createApp(ssrContext, config = {}) {
|
||||
const router = await createRouter(ssrContext, config);
|
||||
|
||||
const store = createStore(ssrContext);
|
||||
|
||||
// Add this.$router into store actions/mutations
|
||||
store.$router = router;
|
||||
|
||||
// Create Root instance
|
||||
|
||||
// here we inject the router and store to all child components,
|
||||
// making them available everywhere as `this.$router` and `this.$store`.
|
||||
const app = {
|
||||
head: {"title":"dashboard","meta":[{"charset":"utf-8"},{"name":"viewport","content":"width=device-width, initial-scale=1"},{"hid":"description","name":"description","content":"Rancher Dashboard"}],"link":[{"hid":"icon","rel":"icon","type":"image\u002Fx-icon","href":"\u002Ffavicon.png"}],"style":[],"script":[]},
|
||||
|
||||
store,
|
||||
router,
|
||||
nuxt: {
|
||||
defaultTransition,
|
||||
transitions: [defaultTransition],
|
||||
setTransitions(transitions) {
|
||||
if (!Array.isArray(transitions)) {
|
||||
transitions = [transitions];
|
||||
}
|
||||
transitions = transitions.map((transition) => {
|
||||
if (!transition) {
|
||||
transition = defaultTransition;
|
||||
} else if (typeof transition === 'string') {
|
||||
transition = Object.assign({}, defaultTransition, { name: transition });
|
||||
} else {
|
||||
transition = Object.assign({}, defaultTransition, transition);
|
||||
}
|
||||
|
||||
return transition;
|
||||
});
|
||||
this.$options.nuxt.transitions = transitions;
|
||||
|
||||
return transitions;
|
||||
},
|
||||
|
||||
err: null,
|
||||
dateErr: null,
|
||||
error(err) {
|
||||
err = err || null;
|
||||
app.context._errored = Boolean(err);
|
||||
err = err ? normalizeError(err) : null;
|
||||
let nuxt = app.nuxt; // to work with @vue/composition-api, see https://github.com/nuxt/nuxt.js/issues/6517#issuecomment-573280207
|
||||
|
||||
if (this) {
|
||||
nuxt = this.nuxt || this.$options.nuxt;
|
||||
}
|
||||
nuxt.dateErr = Date.now();
|
||||
nuxt.err = err;
|
||||
// Used in src/server.js
|
||||
if (ssrContext) {
|
||||
ssrContext.nuxt.error = err;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
},
|
||||
...App
|
||||
};
|
||||
|
||||
// Make app available into store via this.app
|
||||
store.app = app;
|
||||
|
||||
const next = ssrContext ? ssrContext.next : location => app.router.push(location);
|
||||
// Resolve route
|
||||
let route;
|
||||
|
||||
if (ssrContext) {
|
||||
route = router.resolve(ssrContext.url).route;
|
||||
} else {
|
||||
const path = getLocation(router.options.base, router.options.mode);
|
||||
|
||||
route = router.resolve(path).route;
|
||||
}
|
||||
|
||||
// Set context to app.context
|
||||
await setContext(app, {
|
||||
store,
|
||||
route,
|
||||
next,
|
||||
error: app.nuxt.error.bind(app),
|
||||
payload: ssrContext ? ssrContext.payload : undefined,
|
||||
req: ssrContext ? ssrContext.req : undefined,
|
||||
res: ssrContext ? ssrContext.res : undefined,
|
||||
beforeRenderFns: ssrContext ? ssrContext.beforeRenderFns : undefined,
|
||||
ssrContext
|
||||
});
|
||||
|
||||
function inject(key, value) {
|
||||
if (!key) {
|
||||
throw new Error('inject(key, value) has no key provided');
|
||||
}
|
||||
if (value === undefined) {
|
||||
throw new Error(`inject('${ key }', value) has no value provided`);
|
||||
}
|
||||
|
||||
key = `$${ key }`;
|
||||
// Add into app
|
||||
app[key] = value;
|
||||
// Add into context
|
||||
if (!app.context[key]) {
|
||||
app.context[key] = value;
|
||||
}
|
||||
|
||||
// Add into store
|
||||
store[key] = app[key];
|
||||
|
||||
// Check if plugin not already installed
|
||||
const installKey = `__nuxt_${ key }_installed__`;
|
||||
|
||||
if (Vue[installKey]) {
|
||||
return;
|
||||
}
|
||||
Vue[installKey] = true;
|
||||
// Call Vue.use() to install the plugin into vm
|
||||
Vue.use(() => {
|
||||
if (!Object.prototype.hasOwnProperty.call(Vue.prototype, key)) {
|
||||
Object.defineProperty(Vue.prototype, key, {
|
||||
get() {
|
||||
return this.$root.$options[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Inject runtime config as $config
|
||||
inject('config', config);
|
||||
|
||||
if (process.client) {
|
||||
// Replace store state before plugins execution
|
||||
if (window.__NUXT__ && window.__NUXT__.state) {
|
||||
store.replaceState(window.__NUXT__.state);
|
||||
}
|
||||
}
|
||||
|
||||
// Add enablePreview(previewData = {}) in context for plugins
|
||||
if (process.static && process.client) {
|
||||
app.context.enablePreview = function(previewData = {}) {
|
||||
app.previewData = Object.assign({}, previewData);
|
||||
inject('preview', previewData);
|
||||
};
|
||||
}
|
||||
// Plugin execution
|
||||
|
||||
// if (typeof nuxt_plugin_portalvue_6babae27 === 'function') {
|
||||
// await nuxt_plugin_portalvue_6babae27(app.context, inject);
|
||||
// }
|
||||
|
||||
if (typeof cookieUniversalNuxt === 'function') {
|
||||
await cookieUniversalNuxt(app.context, inject);
|
||||
}
|
||||
|
||||
if (typeof axios === 'function') {
|
||||
await axios(app.context, inject);
|
||||
}
|
||||
|
||||
if (typeof plugins === 'function') {
|
||||
await plugins(app.context, inject);
|
||||
}
|
||||
|
||||
if (typeof pluginsLoader === 'function') {
|
||||
await pluginsLoader(app.context, inject);
|
||||
}
|
||||
|
||||
if (typeof axiosShell === 'function') {
|
||||
await axiosShell(app.context, inject);
|
||||
}
|
||||
|
||||
if (process.client && typeof consolePlugin === 'function') {
|
||||
await consolePlugin(app.context, inject);
|
||||
}
|
||||
|
||||
if (process.client && typeof intNumber === 'function') {
|
||||
await intNumber(app.context, inject);
|
||||
}
|
||||
|
||||
if (process.client && typeof nuxtClientInit === 'function') {
|
||||
await nuxtClientInit(app.context, inject);
|
||||
}
|
||||
|
||||
if (typeof replaceAll === 'function') {
|
||||
await replaceAll(app.context, inject);
|
||||
}
|
||||
|
||||
if (typeof backButton === 'function') {
|
||||
await backButton(app.context, inject);
|
||||
}
|
||||
|
||||
if (process.client && typeof plugin === 'function') {
|
||||
await plugin(app.context, inject);
|
||||
}
|
||||
|
||||
if (process.client && typeof codeMirror === 'function') {
|
||||
await codeMirror(app.context, inject);
|
||||
}
|
||||
|
||||
if (process.client && typeof version === 'function') {
|
||||
await version(app.context, inject);
|
||||
}
|
||||
|
||||
if (process.client && typeof steveCreateWorker === 'function') {
|
||||
await steveCreateWorker(app.context, inject);
|
||||
}
|
||||
|
||||
// if (process.client && typeof formatters === 'function') {
|
||||
// await formatters(app.context, inject);
|
||||
// }
|
||||
|
||||
// Lock enablePreview in context
|
||||
if (process.static && process.client) {
|
||||
app.context.enablePreview = function() {
|
||||
console.warn('You cannot call enablePreview() outside a plugin.');
|
||||
};
|
||||
}
|
||||
|
||||
// Wait for async component to be resolved first
|
||||
await new Promise((resolve, reject) => {
|
||||
// Ignore 404s rather than blindly replacing URL in browser
|
||||
if (process.client) {
|
||||
const { route } = router.resolve(app.context.route.fullPath);
|
||||
|
||||
if (!route.matched.length) {
|
||||
return resolve();
|
||||
}
|
||||
}
|
||||
router.replace(app.context.route.fullPath, resolve, (err) => {
|
||||
// https://github.com/vuejs/vue-router/blob/v3.4.3/src/util/errors.js
|
||||
if (!err._isRouter) {
|
||||
return reject(err);
|
||||
}
|
||||
if (err.type !== 2 /* NavigationFailureType.redirected */) {
|
||||
return resolve();
|
||||
}
|
||||
|
||||
// navigated to a different route in router guard
|
||||
const unregister = router.afterEach(async(to, from) => {
|
||||
if (process.server && ssrContext && ssrContext.url) {
|
||||
ssrContext.url = to.fullPath;
|
||||
}
|
||||
app.context.route = await getRouteData(to);
|
||||
app.context.params = to.params || {};
|
||||
app.context.query = to.query || {};
|
||||
unregister();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
store,
|
||||
app,
|
||||
router
|
||||
};
|
||||
}
|
||||
|
||||
export { createApp, NuxtError };
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
const chunks = {} // chunkId => exports
|
||||
const chunksInstalling = {} // chunkId => Promise
|
||||
const failedChunks = {}
|
||||
|
||||
function importChunk(chunkId, src) {
|
||||
// Already installed
|
||||
if (chunks[chunkId]) {
|
||||
return Promise.resolve(chunks[chunkId])
|
||||
}
|
||||
|
||||
// Failed loading
|
||||
if (failedChunks[chunkId]) {
|
||||
return Promise.reject(failedChunks[chunkId])
|
||||
}
|
||||
|
||||
// Installing
|
||||
if (chunksInstalling[chunkId]) {
|
||||
return chunksInstalling[chunkId]
|
||||
}
|
||||
|
||||
// Set a promise in chunk cache
|
||||
let resolve, reject
|
||||
const promise = chunksInstalling[chunkId] = new Promise((_resolve, _reject) => {
|
||||
resolve = _resolve
|
||||
reject = _reject
|
||||
})
|
||||
|
||||
// Clear chunk data from cache
|
||||
delete chunks[chunkId]
|
||||
|
||||
// Start chunk loading
|
||||
const script = document.createElement('script')
|
||||
script.charset = 'utf-8'
|
||||
script.timeout = 120
|
||||
script.src = src
|
||||
let timeout
|
||||
|
||||
// Create error before stack unwound to get useful stacktrace later
|
||||
const error = new Error()
|
||||
|
||||
// Complete handlers
|
||||
const onScriptComplete = script.onerror = script.onload = (event) => {
|
||||
// Cleanups
|
||||
clearTimeout(timeout)
|
||||
delete chunksInstalling[chunkId]
|
||||
|
||||
// Avoid mem leaks in IE
|
||||
script.onerror = script.onload = null
|
||||
|
||||
// Verify chunk is loaded
|
||||
if (chunks[chunkId]) {
|
||||
return resolve(chunks[chunkId])
|
||||
}
|
||||
|
||||
// Something bad happened
|
||||
const errorType = event && (event.type === 'load' ? 'missing' : event.type)
|
||||
const realSrc = event && event.target && event.target.src
|
||||
error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')'
|
||||
error.name = 'ChunkLoadError'
|
||||
error.type = errorType
|
||||
error.request = realSrc
|
||||
failedChunks[chunkId] = error
|
||||
reject(error)
|
||||
}
|
||||
|
||||
// Timeout
|
||||
timeout = setTimeout(() => {
|
||||
onScriptComplete({ type: 'timeout', target: script })
|
||||
}, 120000)
|
||||
|
||||
// Append script
|
||||
document.head.appendChild(script)
|
||||
|
||||
// Return promise
|
||||
return promise
|
||||
}
|
||||
|
||||
export function installJsonp() {
|
||||
window.__NUXT_JSONP__ = function (chunkId, exports) { chunks[chunkId] = exports }
|
||||
window.__NUXT_JSONP_CACHE__ = chunks
|
||||
window.__NUXT_IMPORT__ = importChunk
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
<style>
|
||||
.initial-load-spinner-container {
|
||||
align-items: center;
|
||||
background-color: #f8f8f8;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
.initial-load-spinner {
|
||||
animation: initial-load-animate 1s infinite linear;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
border: 5px solid #008ACF;
|
||||
border-radius: 50%;
|
||||
border-top-color: #00B2E2;
|
||||
display: inline-block;
|
||||
height: 80px;
|
||||
margin: 0 auto;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
@keyframes initial-load-animate {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="initial-load-spinner-container">
|
||||
<i class="initial-load-spinner"></i>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
const middleware = {}
|
||||
|
||||
middleware['authenticated'] = require('../middleware/authenticated.js')
|
||||
middleware['authenticated'] = middleware['authenticated'].default || middleware['authenticated']
|
||||
|
||||
middleware['i18n'] = require('../middleware/i18n.js')
|
||||
middleware['i18n'] = middleware['i18n'].default || middleware['i18n']
|
||||
|
||||
middleware['unauthenticated'] = require('../middleware/unauthenticated.js')
|
||||
middleware['unauthenticated'] = middleware['unauthenticated'].default || middleware['unauthenticated']
|
||||
|
||||
export default middleware
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
import Vue from 'vue'
|
||||
import { hasFetch, normalizeError, addLifecycleHook, createGetCounter } from '../utils'
|
||||
|
||||
const isSsrHydration = (vm) => vm.$vnode && vm.$vnode.elm && vm.$vnode.elm.dataset && vm.$vnode.elm.dataset.fetchKey
|
||||
const nuxtState = window.__NUXT__
|
||||
|
||||
export default {
|
||||
beforeCreate () {
|
||||
if (!hasFetch(this)) {
|
||||
return
|
||||
}
|
||||
|
||||
this._fetchDelay = typeof this.$options.fetchDelay === 'number' ? this.$options.fetchDelay : 200
|
||||
|
||||
Vue.util.defineReactive(this, '$fetchState', {
|
||||
pending: false,
|
||||
error: null,
|
||||
timestamp: Date.now()
|
||||
})
|
||||
|
||||
this.$fetch = $fetch.bind(this)
|
||||
addLifecycleHook(this, 'created', created)
|
||||
addLifecycleHook(this, 'beforeMount', beforeMount)
|
||||
}
|
||||
}
|
||||
|
||||
function beforeMount() {
|
||||
if (!this._hydrated) {
|
||||
return this.$fetch()
|
||||
}
|
||||
}
|
||||
|
||||
function created() {
|
||||
if (!isSsrHydration(this)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Hydrate component
|
||||
this._hydrated = true
|
||||
this._fetchKey = this.$vnode.elm.dataset.fetchKey
|
||||
const data = nuxtState.fetch[this._fetchKey]
|
||||
|
||||
// If fetch error
|
||||
if (data && data._error) {
|
||||
this.$fetchState.error = data._error
|
||||
return
|
||||
}
|
||||
|
||||
// Merge data
|
||||
for (const key in data) {
|
||||
Vue.set(this.$data, key, data[key])
|
||||
}
|
||||
}
|
||||
|
||||
function $fetch() {
|
||||
if (!this._fetchPromise) {
|
||||
this._fetchPromise = $_fetch.call(this)
|
||||
.then(() => { delete this._fetchPromise })
|
||||
}
|
||||
return this._fetchPromise
|
||||
}
|
||||
|
||||
async function $_fetch() {
|
||||
this.$nuxt.nbFetching++
|
||||
this.$fetchState.pending = true
|
||||
this.$fetchState.error = null
|
||||
this._hydrated = false
|
||||
let error = null
|
||||
const startTime = Date.now()
|
||||
|
||||
try {
|
||||
await this.$options.fetch.call(this)
|
||||
} catch (err) {
|
||||
if (process.dev) {
|
||||
console.error('Error in fetch():', err)
|
||||
}
|
||||
error = normalizeError(err)
|
||||
}
|
||||
|
||||
const delayLeft = this._fetchDelay - (Date.now() - startTime)
|
||||
if (delayLeft > 0) {
|
||||
await new Promise(resolve => setTimeout(resolve, delayLeft))
|
||||
}
|
||||
|
||||
this.$fetchState.error = error
|
||||
this.$fetchState.pending = false
|
||||
this.$fetchState.timestamp = Date.now()
|
||||
|
||||
this.$nextTick(() => this.$nuxt.nbFetching--)
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
import Vue from 'vue'
|
||||
import { hasFetch, normalizeError, addLifecycleHook, purifyData, createGetCounter } from '../utils'
|
||||
|
||||
async function serverPrefetch() {
|
||||
if (!this._fetchOnServer) {
|
||||
return
|
||||
}
|
||||
|
||||
// Call and await on $fetch
|
||||
try {
|
||||
await this.$options.fetch.call(this)
|
||||
} catch (err) {
|
||||
if (process.dev) {
|
||||
console.error('Error in fetch():', err)
|
||||
}
|
||||
this.$fetchState.error = normalizeError(err)
|
||||
}
|
||||
this.$fetchState.pending = false
|
||||
|
||||
// Define an ssrKey for hydration
|
||||
this._fetchKey = this._fetchKey || this.$ssrContext.fetchCounters['']++
|
||||
|
||||
// Add data-fetch-key on parent element of Component
|
||||
const attrs = this.$vnode.data.attrs = this.$vnode.data.attrs || {}
|
||||
attrs['data-fetch-key'] = this._fetchKey
|
||||
|
||||
// Add to ssrContext for window.__NUXT__.fetch
|
||||
|
||||
if (this.$ssrContext.nuxt.fetch[this._fetchKey] !== undefined) {
|
||||
console.warn(`Duplicate fetch key detected (${this._fetchKey}). This may lead to unexpected results.`)
|
||||
}
|
||||
|
||||
this.$ssrContext.nuxt.fetch[this._fetchKey] =
|
||||
this.$fetchState.error ? { _error: this.$fetchState.error } : purifyData(this._data)
|
||||
}
|
||||
|
||||
export default {
|
||||
created() {
|
||||
if (!hasFetch(this)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (typeof this.$options.fetchOnServer === 'function') {
|
||||
this._fetchOnServer = this.$options.fetchOnServer.call(this) !== false
|
||||
} else {
|
||||
this._fetchOnServer = this.$options.fetchOnServer !== false
|
||||
}
|
||||
|
||||
const defaultKey = this.$options._scopeId || this.$options.name || ''
|
||||
const getCounter = createGetCounter(this.$ssrContext.fetchCounters, defaultKey)
|
||||
|
||||
if (typeof this.$options.fetchKey === 'function') {
|
||||
this._fetchKey = this.$options.fetchKey.call(this, getCounter)
|
||||
} else {
|
||||
const key = 'string' === typeof this.$options.fetchKey ? this.$options.fetchKey : defaultKey
|
||||
this._fetchKey = key ? key + ':' + getCounter(key) : String(getCounter(key))
|
||||
}
|
||||
|
||||
// Added for remove vue undefined warning while ssr
|
||||
this.$fetch = () => {} // issue #8043
|
||||
Vue.util.defineReactive(this, '$fetchState', {
|
||||
pending: true,
|
||||
error: null,
|
||||
timestamp: Date.now()
|
||||
})
|
||||
|
||||
addLifecycleHook(this, 'serverPrefetch', serverPrefetch)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import Vue from 'vue'
|
||||
import PortalVue from 'portal-vue'
|
||||
|
||||
Vue.use(PortalVue)
|
||||
|
|
@ -0,0 +1,503 @@
|
|||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import { normalizeURL, decode } from 'ufo'
|
||||
import { interopDefault } from './utils'
|
||||
import scrollBehavior from './router.scrollBehavior.js'
|
||||
|
||||
const _b1075e64 = () => interopDefault(import('../pages/about.vue' /* webpackChunkName: "pages/about" */))
|
||||
const _99a1a59e = () => interopDefault(import('../pages/account/index.vue' /* webpackChunkName: "pages/account/index" */))
|
||||
const _10f92ab2 = () => interopDefault(import('../pages/c/index.vue' /* webpackChunkName: "pages/c/index" */))
|
||||
const _0dd7368b = () => interopDefault(import('../pages/clusters/index.vue' /* webpackChunkName: "pages/clusters/index" */))
|
||||
const _a0a6a994 = () => interopDefault(import('../pages/diagnostic.vue' /* webpackChunkName: "pages/diagnostic" */))
|
||||
const _6249d7c9 = () => interopDefault(import('../pages/fail-whale.vue' /* webpackChunkName: "pages/fail-whale" */))
|
||||
const _8d3a64a4 = () => interopDefault(import('../pages/home.vue' /* webpackChunkName: "pages/home" */))
|
||||
const _aa26f31e = () => interopDefault(import('../pages/prefs.vue' /* webpackChunkName: "pages/prefs" */))
|
||||
const _11f3a39f = () => interopDefault(import('../pages/safeMode.vue' /* webpackChunkName: "pages/safeMode" */))
|
||||
const _35190053 = () => interopDefault(import('../pages/support/index.vue' /* webpackChunkName: "pages/support/index" */))
|
||||
const _da172982 = () => interopDefault(import('../pages/account/create-key.vue' /* webpackChunkName: "pages/account/create-key" */))
|
||||
const _35d0be51 = () => interopDefault(import('../pages/auth/login.vue' /* webpackChunkName: "pages/auth/login" */))
|
||||
const _5d4fd75c = () => interopDefault(import('../pages/auth/logout.vue' /* webpackChunkName: "pages/auth/logout" */))
|
||||
const _0da94136 = () => interopDefault(import('../pages/auth/setup.vue' /* webpackChunkName: "pages/auth/setup" */))
|
||||
const _9d01107e = () => interopDefault(import('../pages/auth/verify.vue' /* webpackChunkName: "pages/auth/verify" */))
|
||||
const _52164cec = () => interopDefault(import('../pages/docs/toc.js' /* webpackChunkName: "pages/docs/toc" */))
|
||||
const _06776753 = () => interopDefault(import('../pages/rio/mesh.vue' /* webpackChunkName: "pages/rio/mesh" */))
|
||||
const _2992430e = () => interopDefault(import('../pages/c/_cluster/index.vue' /* webpackChunkName: "pages/c/_cluster/index" */))
|
||||
const _71a3608e = () => interopDefault(import('../pages/docs/_doc.vue' /* webpackChunkName: "pages/docs/_doc" */))
|
||||
const _5efe405e = () => interopDefault(import('../pages/c/_cluster/apps/index.vue' /* webpackChunkName: "pages/c/_cluster/apps/index" */))
|
||||
const _7eff6fd8 = () => interopDefault(import('../pages/c/_cluster/auth/index.vue' /* webpackChunkName: "pages/c/_cluster/auth/index" */))
|
||||
const _20a6f76e = () => interopDefault(import('../pages/c/_cluster/backup/index.vue' /* webpackChunkName: "pages/c/_cluster/backup/index" */))
|
||||
const _ece6af92 = () => interopDefault(import('../pages/c/_cluster/cis/index.vue' /* webpackChunkName: "pages/c/_cluster/cis/index" */))
|
||||
const _89e6b70e = () => interopDefault(import('../pages/c/_cluster/ecm/index.vue' /* webpackChunkName: "pages/c/_cluster/ecm/index" */))
|
||||
const _0561a16b = () => interopDefault(import('../pages/c/_cluster/explorer/index.vue' /* webpackChunkName: "pages/c/_cluster/explorer/index" */))
|
||||
const _9f4d6090 = () => interopDefault(import('../pages/c/_cluster/fleet/index.vue' /* webpackChunkName: "pages/c/_cluster/fleet/index" */))
|
||||
const _0fa0d22e = () => interopDefault(import('../pages/c/_cluster/gatekeeper/index.vue' /* webpackChunkName: "pages/c/_cluster/gatekeeper/index" */))
|
||||
const _1af88b1a = () => interopDefault(import('../pages/c/_cluster/istio/index.vue' /* webpackChunkName: "pages/c/_cluster/istio/index" */))
|
||||
const _3facd8b5 = () => interopDefault(import('../pages/c/_cluster/legacy/index.vue' /* webpackChunkName: "pages/c/_cluster/legacy/index" */))
|
||||
const _24bc84c9 = () => interopDefault(import('../pages/c/_cluster/logging/index.vue' /* webpackChunkName: "pages/c/_cluster/logging/index" */))
|
||||
const _22d2372b = () => interopDefault(import('../pages/c/_cluster/longhorn/index.vue' /* webpackChunkName: "pages/c/_cluster/longhorn/index" */))
|
||||
const _e66f80d2 = () => interopDefault(import('../pages/c/_cluster/manager/index.vue' /* webpackChunkName: "pages/c/_cluster/manager/index" */))
|
||||
const _02abbf34 = () => interopDefault(import('../pages/c/_cluster/mcapps/index.vue' /* webpackChunkName: "pages/c/_cluster/mcapps/index" */))
|
||||
const _e1577418 = () => interopDefault(import('../pages/c/_cluster/monitoring/index.vue' /* webpackChunkName: "pages/c/_cluster/monitoring/index" */))
|
||||
const _4954338b = () => interopDefault(import('../pages/c/_cluster/neuvector/index.vue' /* webpackChunkName: "pages/c/_cluster/neuvector/index" */))
|
||||
const _86270f62 = () => interopDefault(import('../pages/c/_cluster/settings/index.vue' /* webpackChunkName: "pages/c/_cluster/settings/index" */))
|
||||
const _0afff7f6 = () => interopDefault(import('../pages/c/_cluster/uiplugins/index.vue' /* webpackChunkName: "pages/c/_cluster/uiplugins/index" */))
|
||||
const _3cd56cbc = () => interopDefault(import('../pages/c/_cluster/apps/charts/index.vue' /* webpackChunkName: "pages/c/_cluster/apps/charts/index" */))
|
||||
const _11b0721a = () => interopDefault(import('../pages/c/_cluster/auth/config/index.vue' /* webpackChunkName: "pages/c/_cluster/auth/config/index" */))
|
||||
const _25aea87c = () => interopDefault(import('../pages/c/_cluster/auth/roles/index.vue' /* webpackChunkName: "pages/c/_cluster/auth/roles/index" */))
|
||||
const _74341dba = () => interopDefault(import('../pages/c/_cluster/explorer/ConfigBadge.vue' /* webpackChunkName: "pages/c/_cluster/explorer/ConfigBadge" */))
|
||||
const _14bdf46e = () => interopDefault(import('../pages/c/_cluster/explorer/EventsTable.vue' /* webpackChunkName: "pages/c/_cluster/explorer/EventsTable" */))
|
||||
const _a75fe116 = () => interopDefault(import('../pages/c/_cluster/explorer/explorer-utils.js' /* webpackChunkName: "pages/c/_cluster/explorer/explorer-utils" */))
|
||||
const _01865512 = () => interopDefault(import('../pages/c/_cluster/explorer/tools/index.vue' /* webpackChunkName: "pages/c/_cluster/explorer/tools/index" */))
|
||||
const _9c418d0e = () => interopDefault(import('../pages/c/_cluster/fleet/GitRepoGraphConfig.js' /* webpackChunkName: "pages/c/_cluster/fleet/GitRepoGraphConfig" */))
|
||||
const _f1812060 = () => interopDefault(import('../pages/c/_cluster/gatekeeper/constraints/index.vue' /* webpackChunkName: "pages/c/_cluster/gatekeeper/constraints/index" */))
|
||||
const _b539bb82 = () => interopDefault(import('../pages/c/_cluster/legacy/project/index.vue' /* webpackChunkName: "pages/c/_cluster/legacy/project/index" */))
|
||||
const _44fb97b4 = () => interopDefault(import('../pages/c/_cluster/manager/cloudCredential/index.vue' /* webpackChunkName: "pages/c/_cluster/manager/cloudCredential/index" */))
|
||||
const _17ce10e4 = () => interopDefault(import('../pages/c/_cluster/monitoring/alertmanagerconfig/index.vue' /* webpackChunkName: "pages/c/_cluster/monitoring/alertmanagerconfig/index" */))
|
||||
const _57f0357f = () => interopDefault(import('../pages/c/_cluster/monitoring/monitor/index.vue' /* webpackChunkName: "pages/c/_cluster/monitoring/monitor/index" */))
|
||||
const _acf430f8 = () => interopDefault(import('../pages/c/_cluster/monitoring/route-receiver/index.vue' /* webpackChunkName: "pages/c/_cluster/monitoring/route-receiver/index" */))
|
||||
const _9c1862f8 = () => interopDefault(import('../pages/c/_cluster/settings/banners.vue' /* webpackChunkName: "pages/c/_cluster/settings/banners" */))
|
||||
const _83bd8ef8 = () => interopDefault(import('../pages/c/_cluster/settings/brand.vue' /* webpackChunkName: "pages/c/_cluster/settings/brand" */))
|
||||
const _6ace98ec = () => interopDefault(import('../pages/c/_cluster/settings/DefaultLinksEditor.vue' /* webpackChunkName: "shell/pages/c/_cluster/settings/DefaultLinksEditor" */))
|
||||
const _e56e5894 = () => interopDefault(import('../pages/c/_cluster/settings/links.vue' /* webpackChunkName: "pages/c/_cluster/settings/links" */))
|
||||
const _0ff4c0ed = () => interopDefault(import('../pages/c/_cluster/settings/performance.vue' /* webpackChunkName: "pages/c/_cluster/settings/performance" */))
|
||||
const _978f0576 = () => interopDefault(import('../pages/c/_cluster/uiplugins/DeveloperInstallDialog.vue' /* webpackChunkName: "pages/c/_cluster/uiplugins/DeveloperInstallDialog" */))
|
||||
const _256d9147 = () => interopDefault(import('../pages/c/_cluster/uiplugins/InstallDialog.vue' /* webpackChunkName: "pages/c/_cluster/uiplugins/InstallDialog" */))
|
||||
const _f6d8b8f2 = () => interopDefault(import('../pages/c/_cluster/uiplugins/PluginInfoPanel.vue' /* webpackChunkName: "pages/c/_cluster/uiplugins/PluginInfoPanel" */))
|
||||
const _33e16f6c = () => interopDefault(import('../pages/c/_cluster/uiplugins/RemoveUIPlugins.vue' /* webpackChunkName: "pages/c/_cluster/uiplugins/RemoveUIPlugins" */))
|
||||
const _d7c9a08a = () => interopDefault(import('../pages/c/_cluster/uiplugins/SetupUIPlugins.vue' /* webpackChunkName: "pages/c/_cluster/uiplugins/SetupUIPlugins" */))
|
||||
const _266ebcce = () => interopDefault(import('../pages/c/_cluster/uiplugins/UninstallDialog.vue' /* webpackChunkName: "pages/c/_cluster/uiplugins/UninstallDialog" */))
|
||||
const _69909470 = () => interopDefault(import('../pages/c/_cluster/apps/charts/chart.vue' /* webpackChunkName: "pages/c/_cluster/apps/charts/chart" */))
|
||||
const _685cdef6 = () => interopDefault(import('../pages/c/_cluster/apps/charts/install.vue' /* webpackChunkName: "pages/c/_cluster/apps/charts/install" */))
|
||||
const _5e92cb4c = () => interopDefault(import('../pages/c/_cluster/auth/group.principal/assign-edit.vue' /* webpackChunkName: "pages/c/_cluster/auth/group.principal/assign-edit" */))
|
||||
const _97480d04 = () => interopDefault(import('../pages/c/_cluster/legacy/project/pipelines.vue' /* webpackChunkName: "pages/c/_cluster/legacy/project/pipelines" */))
|
||||
const _fba8acec = () => interopDefault(import('../pages/c/_cluster/manager/cloudCredential/create.vue' /* webpackChunkName: "pages/c/_cluster/manager/cloudCredential/create" */))
|
||||
const _646a75c2 = () => interopDefault(import('../pages/c/_cluster/monitoring/monitor/create.vue' /* webpackChunkName: "pages/c/_cluster/monitoring/monitor/create" */))
|
||||
const _a229588c = () => interopDefault(import('../pages/c/_cluster/monitoring/route-receiver/create.vue' /* webpackChunkName: "pages/c/_cluster/monitoring/route-receiver/create" */))
|
||||
const _24eaabc8 = () => interopDefault(import('../pages/c/_cluster/explorer/tools/pages/_page.vue' /* webpackChunkName: "pages/c/_cluster/explorer/tools/pages/_page" */))
|
||||
const _77d0ea1b = () => interopDefault(import('../pages/c/_cluster/auth/config/_id.vue' /* webpackChunkName: "pages/c/_cluster/auth/config/_id" */))
|
||||
const _58626ef4 = () => interopDefault(import('../pages/c/_cluster/legacy/pages/_page.vue' /* webpackChunkName: "pages/c/_cluster/legacy/pages/_page" */))
|
||||
const _0e2466db = () => interopDefault(import('../pages/c/_cluster/legacy/project/_page.vue' /* webpackChunkName: "pages/c/_cluster/legacy/project/_page" */))
|
||||
const _5b9811c8 = () => interopDefault(import('../pages/c/_cluster/manager/cloudCredential/_id.vue' /* webpackChunkName: "pages/c/_cluster/manager/cloudCredential/_id" */))
|
||||
const _0f85fde8 = () => interopDefault(import('../pages/c/_cluster/manager/pages/_page.vue' /* webpackChunkName: "pages/c/_cluster/manager/pages/_page" */))
|
||||
const _107ed876 = () => interopDefault(import('../pages/c/_cluster/mcapps/pages/_page.vue' /* webpackChunkName: "pages/c/_cluster/mcapps/pages/_page" */))
|
||||
const _f12c4b3c = () => interopDefault(import('../pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/index.vue' /* webpackChunkName: "pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/index" */))
|
||||
const _25affaec = () => interopDefault(import('../pages/c/_cluster/monitoring/route-receiver/_id.vue' /* webpackChunkName: "pages/c/_cluster/monitoring/route-receiver/_id" */))
|
||||
const _0e9569c4 = () => interopDefault(import('../pages/c/_cluster/auth/roles/_resource/create.vue' /* webpackChunkName: "pages/c/_cluster/auth/roles/_resource/create" */))
|
||||
const _0d1a9be2 = () => interopDefault(import('../pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/receiver.vue' /* webpackChunkName: "pages/c/_cluster/monitoring/alertmanagerconfig/_alertmanagerconfigid/receiver" */))
|
||||
const _1643de08 = () => interopDefault(import('../pages/c/_cluster/auth/roles/_resource/_id.vue' /* webpackChunkName: "pages/c/_cluster/auth/roles/_resource/_id" */))
|
||||
const _30293caa = () => interopDefault(import('../pages/c/_cluster/monitoring/monitor/_namespace/_id.vue' /* webpackChunkName: "pages/c/_cluster/monitoring/monitor/_namespace/_id" */))
|
||||
const _3dcc28a0 = () => interopDefault(import('../pages/c/_cluster/navlinks/_group.vue' /* webpackChunkName: "pages/c/_cluster/navlinks/_group" */))
|
||||
const _327638c8 = () => interopDefault(import('../pages/c/_cluster/_product/index.vue' /* webpackChunkName: "pages/c/_cluster/_product/index" */))
|
||||
const _3feb57b4 = () => interopDefault(import('../pages/c/_cluster/_product/members/index.vue' /* webpackChunkName: "pages/c/_cluster/_product/members/index" */))
|
||||
const _2e2d89c4 = () => interopDefault(import('../pages/c/_cluster/_product/namespaces.vue' /* webpackChunkName: "pages/c/_cluster/_product/namespaces" */))
|
||||
const _76d90818 = () => interopDefault(import('../pages/c/_cluster/_product/projectsnamespaces.vue' /* webpackChunkName: "pages/c/_cluster/_product/projectsnamespaces" */))
|
||||
const _587122fa = () => interopDefault(import('../pages/c/_cluster/_product/_resource/index.vue' /* webpackChunkName: "pages/c/_cluster/_product/_resource/index" */))
|
||||
const _4530f1f8 = () => interopDefault(import('../pages/c/_cluster/_product/_resource/create.vue' /* webpackChunkName: "pages/c/_cluster/_product/_resource/create" */))
|
||||
const _ac00c83c = () => interopDefault(import('../pages/c/_cluster/_product/_resource/_id.vue' /* webpackChunkName: "pages/c/_cluster/_product/_resource/_id" */))
|
||||
const _1cac498f = () => interopDefault(import('../pages/c/_cluster/_product/_resource/_namespace/_id.vue' /* webpackChunkName: "pages/c/_cluster/_product/_resource/_namespace/_id" */))
|
||||
const _7197a8da = () => interopDefault(import('../pages/index.vue' /* webpackChunkName: "pages/index" */))
|
||||
|
||||
const emptyFn = () => {}
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
export const routerOptions = {
|
||||
mode: 'history',
|
||||
base: '/',
|
||||
linkActiveClass: 'nuxt-link-active',
|
||||
linkExactActiveClass: 'nuxt-link-exact-active',
|
||||
scrollBehavior,
|
||||
|
||||
routes: [{
|
||||
path: "/about",
|
||||
component: _b1075e64,
|
||||
name: "about"
|
||||
}, {
|
||||
path: "/account",
|
||||
component: _99a1a59e,
|
||||
name: "account"
|
||||
}, {
|
||||
path: "/c",
|
||||
component: _10f92ab2,
|
||||
name: "c"
|
||||
}, {
|
||||
path: "/clusters",
|
||||
component: _0dd7368b,
|
||||
name: "clusters"
|
||||
}, {
|
||||
path: "/diagnostic",
|
||||
component: _a0a6a994,
|
||||
name: "diagnostic"
|
||||
}, {
|
||||
path: "/fail-whale",
|
||||
component: _6249d7c9,
|
||||
name: "fail-whale"
|
||||
}, {
|
||||
path: "/home",
|
||||
component: _8d3a64a4,
|
||||
name: "home"
|
||||
}, {
|
||||
path: "/prefs",
|
||||
component: _aa26f31e,
|
||||
name: "prefs"
|
||||
}, {
|
||||
path: "/safeMode",
|
||||
component: _11f3a39f,
|
||||
name: "safeMode"
|
||||
}, {
|
||||
path: "/support",
|
||||
component: _35190053,
|
||||
name: "support"
|
||||
}, {
|
||||
path: "/account/create-key",
|
||||
component: _da172982,
|
||||
name: "account-create-key"
|
||||
}, {
|
||||
path: "/auth/login",
|
||||
component: _35d0be51,
|
||||
name: "auth-login"
|
||||
}, {
|
||||
path: "/auth/logout",
|
||||
component: _5d4fd75c,
|
||||
name: "auth-logout"
|
||||
}, {
|
||||
path: "/auth/setup",
|
||||
component: _0da94136,
|
||||
name: "auth-setup"
|
||||
}, {
|
||||
path: "/auth/verify",
|
||||
component: _9d01107e,
|
||||
name: "auth-verify"
|
||||
}, {
|
||||
path: "/docs/toc",
|
||||
component: _52164cec,
|
||||
name: "docs-toc"
|
||||
}, {
|
||||
path: "/rio/mesh",
|
||||
component: _06776753,
|
||||
name: "rio-mesh"
|
||||
}, {
|
||||
path: "/c/:cluster",
|
||||
component: _2992430e,
|
||||
name: "c-cluster"
|
||||
}, {
|
||||
path: "/docs/:doc?",
|
||||
component: _71a3608e,
|
||||
name: "docs-doc"
|
||||
}, {
|
||||
path: "/c/:cluster/apps",
|
||||
component: _5efe405e,
|
||||
name: "c-cluster-apps"
|
||||
}, {
|
||||
path: "/c/:cluster/auth",
|
||||
component: _7eff6fd8,
|
||||
name: "c-cluster-auth"
|
||||
}, {
|
||||
path: "/c/:cluster/backup",
|
||||
component: _20a6f76e,
|
||||
name: "c-cluster-backup"
|
||||
}, {
|
||||
path: "/c/:cluster/cis",
|
||||
component: _ece6af92,
|
||||
name: "c-cluster-cis"
|
||||
}, {
|
||||
path: "/c/:cluster/ecm",
|
||||
component: _89e6b70e,
|
||||
name: "c-cluster-ecm"
|
||||
}, {
|
||||
path: "/c/:cluster/explorer",
|
||||
component: _0561a16b,
|
||||
name: "c-cluster-explorer"
|
||||
}, {
|
||||
path: "/c/:cluster/fleet",
|
||||
component: _9f4d6090,
|
||||
name: "c-cluster-fleet"
|
||||
}, {
|
||||
path: "/c/:cluster/gatekeeper",
|
||||
component: _0fa0d22e,
|
||||
name: "c-cluster-gatekeeper"
|
||||
}, {
|
||||
path: "/c/:cluster/istio",
|
||||
component: _1af88b1a,
|
||||
name: "c-cluster-istio"
|
||||
}, {
|
||||
path: "/c/:cluster/legacy",
|
||||
component: _3facd8b5,
|
||||
name: "c-cluster-legacy"
|
||||
}, {
|
||||
path: "/c/:cluster/logging",
|
||||
component: _24bc84c9,
|
||||
name: "c-cluster-logging"
|
||||
}, {
|
||||
path: "/c/:cluster/longhorn",
|
||||
component: _22d2372b,
|
||||
name: "c-cluster-longhorn"
|
||||
}, {
|
||||
path: "/c/:cluster/manager",
|
||||
component: _e66f80d2,
|
||||
name: "c-cluster-manager"
|
||||
}, {
|
||||
path: "/c/:cluster/mcapps",
|
||||
component: _02abbf34,
|
||||
name: "c-cluster-mcapps"
|
||||
}, {
|
||||
path: "/c/:cluster/monitoring",
|
||||
component: _e1577418,
|
||||
name: "c-cluster-monitoring"
|
||||
}, {
|
||||
path: "/c/:cluster/neuvector",
|
||||
component: _4954338b,
|
||||
name: "c-cluster-neuvector"
|
||||
}, {
|
||||
path: "/c/:cluster/settings",
|
||||
component: _86270f62,
|
||||
name: "c-cluster-settings"
|
||||
}, {
|
||||
path: "/c/:cluster/uiplugins",
|
||||
component: _0afff7f6,
|
||||
name: "c-cluster-uiplugins"
|
||||
}, {
|
||||
path: "/c/:cluster/apps/charts",
|
||||
component: _3cd56cbc,
|
||||
name: "c-cluster-apps-charts"
|
||||
}, {
|
||||
path: "/c/:cluster/auth/config",
|
||||
component: _11b0721a,
|
||||
name: "c-cluster-auth-config"
|
||||
}, {
|
||||
path: "/c/:cluster/auth/roles",
|
||||
component: _25aea87c,
|
||||
name: "c-cluster-auth-roles"
|
||||
}, {
|
||||
path: "/c/:cluster/explorer/ConfigBadge",
|
||||
component: _74341dba,
|
||||
name: "c-cluster-explorer-ConfigBadge"
|
||||
}, {
|
||||
path: "/c/:cluster/explorer/EventsTable",
|
||||
component: _14bdf46e,
|
||||
name: "c-cluster-explorer-EventsTable"
|
||||
}, {
|
||||
path: "/c/:cluster/explorer/explorer-utils",
|
||||
component: _a75fe116,
|
||||
name: "c-cluster-explorer-explorer-utils"
|
||||
}, {
|
||||
path: "/c/:cluster/explorer/tools",
|
||||
component: _01865512,
|
||||
name: "c-cluster-explorer-tools"
|
||||
}, {
|
||||
path: "/c/:cluster/fleet/GitRepoGraphConfig",
|
||||
component: _9c418d0e,
|
||||
name: "c-cluster-fleet-GitRepoGraphConfig"
|
||||
}, {
|
||||
path: "/c/:cluster/gatekeeper/constraints",
|
||||
component: _f1812060,
|
||||
name: "c-cluster-gatekeeper-constraints"
|
||||
}, {
|
||||
path: "/c/:cluster/legacy/project",
|
||||
component: _b539bb82,
|
||||
name: "c-cluster-legacy-project"
|
||||
}, {
|
||||
path: "/c/:cluster/manager/cloudCredential",
|
||||
component: _44fb97b4,
|
||||
name: "c-cluster-manager-cloudCredential"
|
||||
}, {
|
||||
path: "/c/:cluster/monitoring/alertmanagerconfig",
|
||||
component: _17ce10e4,
|
||||
name: "c-cluster-monitoring-alertmanagerconfig"
|
||||
}, {
|
||||
path: "/c/:cluster/monitoring/monitor",
|
||||
component: _57f0357f,
|
||||
name: "c-cluster-monitoring-monitor"
|
||||
}, {
|
||||
path: "/c/:cluster/monitoring/route-receiver",
|
||||
component: _acf430f8,
|
||||
name: "c-cluster-monitoring-route-receiver"
|
||||
}, {
|
||||
path: "/c/:cluster/settings/banners",
|
||||
component: _9c1862f8,
|
||||
name: "c-cluster-settings-banners"
|
||||
}, {
|
||||
path: "/c/:cluster/settings/brand",
|
||||
component: _83bd8ef8,
|
||||
name: "c-cluster-settings-brand"
|
||||
}, {
|
||||
path: "/c/:cluster/settings/DefaultLinksEditor",
|
||||
component: _6ace98ec,
|
||||
name: "c-cluster-settings-DefaultLinksEditor"
|
||||
}, {
|
||||
path: "/c/:cluster/settings/links",
|
||||
component: _e56e5894,
|
||||
name: "c-cluster-settings-links"
|
||||
}, {
|
||||
path: "/c/:cluster/settings/performance",
|
||||
component: _0ff4c0ed,
|
||||
name: "c-cluster-settings-performance"
|
||||
}, {
|
||||
path: "/c/:cluster/uiplugins/DeveloperInstallDialog",
|
||||
component: _978f0576,
|
||||
name: "c-cluster-uiplugins-DeveloperInstallDialog"
|
||||
}, {
|
||||
path: "/c/:cluster/uiplugins/InstallDialog",
|
||||
component: _256d9147,
|
||||
name: "c-cluster-uiplugins-InstallDialog"
|
||||
}, {
|
||||
path: "/c/:cluster/uiplugins/PluginInfoPanel",
|
||||
component: _f6d8b8f2,
|
||||
name: "c-cluster-uiplugins-PluginInfoPanel"
|
||||
}, {
|
||||
path: "/c/:cluster/uiplugins/RemoveUIPlugins",
|
||||
component: _33e16f6c,
|
||||
name: "c-cluster-uiplugins-RemoveUIPlugins"
|
||||
}, {
|
||||
path: "/c/:cluster/uiplugins/SetupUIPlugins",
|
||||
component: _d7c9a08a,
|
||||
name: "c-cluster-uiplugins-SetupUIPlugins"
|
||||
}, {
|
||||
path: "/c/:cluster/uiplugins/UninstallDialog",
|
||||
component: _266ebcce,
|
||||
name: "c-cluster-uiplugins-UninstallDialog"
|
||||
}, {
|
||||
path: "/c/:cluster/apps/charts/chart",
|
||||
component: _69909470,
|
||||
name: "c-cluster-apps-charts-chart"
|
||||
}, {
|
||||
path: "/c/:cluster/apps/charts/install",
|
||||
component: _685cdef6,
|
||||
name: "c-cluster-apps-charts-install"
|
||||
}, {
|
||||
path: "/c/:cluster/auth/group.principal/assign-edit",
|
||||
component: _5e92cb4c,
|
||||
name: "c-cluster-auth-group.principal-assign-edit"
|
||||
}, {
|
||||
path: "/c/:cluster/legacy/project/pipelines",
|
||||
component: _97480d04,
|
||||
name: "c-cluster-legacy-project-pipelines"
|
||||
}, {
|
||||
path: "/c/:cluster/manager/cloudCredential/create",
|
||||
component: _fba8acec,
|
||||
name: "c-cluster-manager-cloudCredential-create"
|
||||
}, {
|
||||
path: "/c/:cluster/monitoring/monitor/create",
|
||||
component: _646a75c2,
|
||||
name: "c-cluster-monitoring-monitor-create"
|
||||
}, {
|
||||
path: "/c/:cluster/monitoring/route-receiver/create",
|
||||
component: _a229588c,
|
||||
name: "c-cluster-monitoring-route-receiver-create"
|
||||
}, {
|
||||
path: "/c/:cluster/explorer/tools/pages/:page?",
|
||||
component: _24eaabc8,
|
||||
name: "c-cluster-explorer-tools-pages-page"
|
||||
}, {
|
||||
path: "/c/:cluster/auth/config/:id",
|
||||
component: _77d0ea1b,
|
||||
name: "c-cluster-auth-config-id"
|
||||
}, {
|
||||
path: "/c/:cluster/legacy/pages/:page?",
|
||||
component: _58626ef4,
|
||||
name: "c-cluster-legacy-pages-page"
|
||||
}, {
|
||||
path: "/c/:cluster/legacy/project/:page",
|
||||
component: _0e2466db,
|
||||
name: "c-cluster-legacy-project-page"
|
||||
}, {
|
||||
path: "/c/:cluster/manager/cloudCredential/:id",
|
||||
component: _5b9811c8,
|
||||
name: "c-cluster-manager-cloudCredential-id"
|
||||
}, {
|
||||
path: "/c/:cluster/manager/pages/:page?",
|
||||
component: _0f85fde8,
|
||||
name: "c-cluster-manager-pages-page"
|
||||
}, {
|
||||
path: "/c/:cluster/mcapps/pages/:page?",
|
||||
component: _107ed876,
|
||||
name: "c-cluster-mcapps-pages-page"
|
||||
}, {
|
||||
path: "/c/:cluster/monitoring/alertmanagerconfig/:alertmanagerconfigid",
|
||||
component: _f12c4b3c,
|
||||
name: "c-cluster-monitoring-alertmanagerconfig-alertmanagerconfigid"
|
||||
}, {
|
||||
path: "/c/:cluster/monitoring/route-receiver/:id?",
|
||||
component: _25affaec,
|
||||
name: "c-cluster-monitoring-route-receiver-id"
|
||||
}, {
|
||||
path: "/c/:cluster/auth/roles/:resource/create",
|
||||
component: _0e9569c4,
|
||||
name: "c-cluster-auth-roles-resource-create"
|
||||
}, {
|
||||
path: "/c/:cluster/monitoring/alertmanagerconfig/:alertmanagerconfigid/receiver",
|
||||
component: _0d1a9be2,
|
||||
name: "c-cluster-monitoring-alertmanagerconfig-alertmanagerconfigid-receiver"
|
||||
}, {
|
||||
path: "/c/:cluster/auth/roles/:resource/:id?",
|
||||
component: _1643de08,
|
||||
name: "c-cluster-auth-roles-resource-id"
|
||||
}, {
|
||||
path: "/c/:cluster/monitoring/monitor/:namespace/:id?",
|
||||
component: _30293caa,
|
||||
name: "c-cluster-monitoring-monitor-namespace-id"
|
||||
}, {
|
||||
path: "/c/:cluster/navlinks/:group?",
|
||||
component: _3dcc28a0,
|
||||
name: "c-cluster-navlinks-group"
|
||||
}, {
|
||||
path: "/c/:cluster/:product",
|
||||
component: _327638c8,
|
||||
name: "c-cluster-product"
|
||||
}, {
|
||||
path: "/c/:cluster/:product/members",
|
||||
component: _3feb57b4,
|
||||
name: "c-cluster-product-members"
|
||||
}, {
|
||||
path: "/c/:cluster/:product/namespaces",
|
||||
component: _2e2d89c4,
|
||||
name: "c-cluster-product-namespaces"
|
||||
}, {
|
||||
path: "/c/:cluster/:product/projectsnamespaces",
|
||||
component: _76d90818,
|
||||
name: "c-cluster-product-projectsnamespaces"
|
||||
}, {
|
||||
path: "/c/:cluster/:product/:resource",
|
||||
component: _587122fa,
|
||||
name: "c-cluster-product-resource"
|
||||
}, {
|
||||
path: "/c/:cluster/:product/:resource/create",
|
||||
component: _4530f1f8,
|
||||
name: "c-cluster-product-resource-create"
|
||||
}, {
|
||||
path: "/c/:cluster/:product/:resource/:id",
|
||||
component: _ac00c83c,
|
||||
name: "c-cluster-product-resource-id"
|
||||
}, {
|
||||
path: "/c/:cluster/:product/:resource/:namespace/:id?",
|
||||
component: _1cac498f,
|
||||
name: "c-cluster-product-resource-namespace-id"
|
||||
}, {
|
||||
path: "/",
|
||||
component: _7197a8da,
|
||||
name: "index"
|
||||
}],
|
||||
|
||||
fallback: false
|
||||
}
|
||||
|
||||
export function createRouter (ssrContext, config) {
|
||||
const base = (config._app && config._app.basePath) || routerOptions.base
|
||||
const router = new Router({ ...routerOptions, base })
|
||||
|
||||
// TODO: remove in Nuxt 3
|
||||
const originalPush = router.push
|
||||
router.push = function push (location, onComplete = emptyFn, onAbort) {
|
||||
return originalPush.call(this, location, onComplete, onAbort)
|
||||
}
|
||||
|
||||
const resolve = router.resolve.bind(router)
|
||||
router.resolve = (to, current, append) => {
|
||||
if (typeof to === 'string') {
|
||||
to = normalizeURL(to)
|
||||
}
|
||||
return resolve(to, current, append)
|
||||
}
|
||||
|
||||
return router
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
import { getMatchedComponents, setScrollRestoration } from './utils'
|
||||
|
||||
if (process.client) {
|
||||
if ('scrollRestoration' in window.history) {
|
||||
setScrollRestoration('manual')
|
||||
|
||||
// reset scrollRestoration to auto when leaving page, allowing page reload
|
||||
// and back-navigation from other pages to use the browser to restore the
|
||||
// scrolling position.
|
||||
window.addEventListener('beforeunload', () => {
|
||||
setScrollRestoration('auto')
|
||||
})
|
||||
|
||||
// Setting scrollRestoration to manual again when returning to this page.
|
||||
window.addEventListener('load', () => {
|
||||
setScrollRestoration('manual')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function shouldScrollToTop(route) {
|
||||
const Pages = getMatchedComponents(route)
|
||||
if (Pages.length === 1) {
|
||||
const { options = {} } = Pages[0]
|
||||
return options.scrollToTop !== false
|
||||
}
|
||||
return Pages.some(({ options }) => options && options.scrollToTop)
|
||||
}
|
||||
|
||||
export default function (to, from, savedPosition) {
|
||||
// If the returned position is falsy or an empty object, will retain current scroll position
|
||||
let position = false
|
||||
const isRouteChanged = to !== from
|
||||
|
||||
// savedPosition is only available for popstate navigations (back button)
|
||||
if (savedPosition) {
|
||||
position = savedPosition
|
||||
} else if (isRouteChanged && shouldScrollToTop(to)) {
|
||||
position = { x: 0, y: 0 }
|
||||
}
|
||||
|
||||
const nuxt = window.$nuxt
|
||||
|
||||
if (
|
||||
// Initial load (vuejs/vue-router#3199)
|
||||
!isRouteChanged ||
|
||||
// Route hash changes
|
||||
(to.path === from.path && to.hash !== from.hash)
|
||||
) {
|
||||
nuxt.$nextTick(() => nuxt.$emit('triggerScroll'))
|
||||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
// wait for the out transition to complete (if necessary)
|
||||
nuxt.$once('triggerScroll', () => {
|
||||
// coords will be used if no selector is provided,
|
||||
// or if the selector didn't match any element.
|
||||
if (to.hash) {
|
||||
let hash = to.hash
|
||||
// CSS.escape() is not supported with IE and Edge.
|
||||
if (typeof window.CSS !== 'undefined' && typeof window.CSS.escape !== 'undefined') {
|
||||
hash = '#' + window.CSS.escape(hash.substr(1))
|
||||
}
|
||||
try {
|
||||
if (document.querySelector(hash)) {
|
||||
// scroll to anchor by returning the selector
|
||||
position = { selector: hash }
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to save scroll position. Please add CSS.escape() polyfill (https://github.com/mathiasbynens/CSS.escape).')
|
||||
}
|
||||
}
|
||||
resolve(position)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
import Vue from 'vue'
|
||||
import { joinURL, normalizeURL, withQuery } from 'ufo'
|
||||
import fetch from 'node-fetch'
|
||||
import middleware from './middleware.js'
|
||||
import {
|
||||
applyAsyncData,
|
||||
middlewareSeries,
|
||||
sanitizeComponent,
|
||||
getMatchedComponents,
|
||||
promisify
|
||||
} from './utils.js'
|
||||
import fetchMixin from './mixins/fetch.server'
|
||||
import { createApp, NuxtError } from './index.js'
|
||||
import NuxtLink from './components/nuxt-link.server.js' // should be included after ./index.js
|
||||
|
||||
// Update serverPrefetch strategy
|
||||
Vue.config.optionMergeStrategies.serverPrefetch = Vue.config.optionMergeStrategies.created
|
||||
|
||||
// Fetch mixin
|
||||
if (!Vue.__nuxt__fetch__mixin__) {
|
||||
Vue.mixin(fetchMixin)
|
||||
Vue.__nuxt__fetch__mixin__ = true
|
||||
}
|
||||
|
||||
if (!Vue.__original_use__) {
|
||||
Vue.__original_use__ = Vue.use
|
||||
Vue.__install_times__ = 0
|
||||
Vue.use = function (plugin, ...args) {
|
||||
plugin.__nuxt_external_installed__ = Vue._installedPlugins.includes(plugin)
|
||||
return Vue.__original_use__(plugin, ...args)
|
||||
}
|
||||
}
|
||||
if (Vue.__install_times__ === 2) {
|
||||
Vue.__install_times__ = 0
|
||||
Vue._installedPlugins = Vue._installedPlugins.filter(plugin => {
|
||||
return plugin.__nuxt_external_installed__ === true
|
||||
})
|
||||
}
|
||||
Vue.__install_times__++
|
||||
|
||||
// Component: <NuxtLink>
|
||||
Vue.component(NuxtLink.name, NuxtLink)
|
||||
Vue.component('NLink', NuxtLink)
|
||||
|
||||
if (!global.fetch) { global.fetch = fetch }
|
||||
|
||||
const noopApp = () => new Vue({ render: h => h('div', { domProps: { id: '__nuxt' } }) })
|
||||
|
||||
const createNext = ssrContext => (opts) => {
|
||||
// If static target, render on client-side
|
||||
ssrContext.redirected = opts
|
||||
if (ssrContext.target === 'static' || !ssrContext.res) {
|
||||
ssrContext.nuxt.serverRendered = false
|
||||
return
|
||||
}
|
||||
let fullPath = withQuery(opts.path, opts.query)
|
||||
const $config = ssrContext.runtimeConfig || {}
|
||||
const routerBase = ($config._app && $config._app.basePath) || '/'
|
||||
if (!fullPath.startsWith('http') && (routerBase !== '/' && !fullPath.startsWith(routerBase))) {
|
||||
fullPath = joinURL(routerBase, fullPath)
|
||||
}
|
||||
// Avoid loop redirect
|
||||
if (decodeURI(fullPath) === decodeURI(ssrContext.url)) {
|
||||
ssrContext.redirected = false
|
||||
return
|
||||
}
|
||||
ssrContext.res.writeHead(opts.status, {
|
||||
Location: normalizeURL(fullPath)
|
||||
})
|
||||
ssrContext.res.end()
|
||||
}
|
||||
|
||||
// This exported function will be called by `bundleRenderer`.
|
||||
// This is where we perform data-prefetching to determine the
|
||||
// state of our application before actually rendering it.
|
||||
// Since data fetching is async, this function is expected to
|
||||
// return a Promise that resolves to the app instance.
|
||||
export default async (ssrContext) => {
|
||||
// Create ssrContext.next for simulate next() of beforeEach() when wanted to redirect
|
||||
ssrContext.redirected = false
|
||||
ssrContext.next = createNext(ssrContext)
|
||||
// Used for beforeNuxtRender({ Components, nuxtState })
|
||||
ssrContext.beforeRenderFns = []
|
||||
// Nuxt object (window.{{globals.context}}, defaults to window.__NUXT__)
|
||||
ssrContext.nuxt = { layout: 'default', data: [], fetch: {}, error: null, state: null, serverRendered: true, routePath: '' }
|
||||
|
||||
ssrContext.fetchCounters = {}
|
||||
|
||||
// Remove query from url is static target
|
||||
|
||||
// Public runtime config
|
||||
ssrContext.nuxt.config = ssrContext.runtimeConfig.public
|
||||
if (ssrContext.nuxt.config._app) {
|
||||
__webpack_public_path__ = joinURL(ssrContext.nuxt.config._app.cdnURL, ssrContext.nuxt.config._app.assetsPath)
|
||||
}
|
||||
// Create the app definition and the instance (created for each request)
|
||||
const { app, router, store } = await createApp(ssrContext, ssrContext.runtimeConfig.private)
|
||||
const _app = new Vue(app)
|
||||
// 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
|
||||
|
||||
// Add meta infos (used in renderer.js)
|
||||
ssrContext.meta = _app.$meta()
|
||||
|
||||
// Keep asyncData for each matched component in ssrContext (used in app/utils.js via this.$ssrContext)
|
||||
ssrContext.asyncData = {}
|
||||
|
||||
const beforeRender = async () => {
|
||||
// Call beforeNuxtRender() methods
|
||||
await Promise.all(ssrContext.beforeRenderFns.map(fn => promisify(fn, { Components, nuxtState: ssrContext.nuxt })))
|
||||
|
||||
ssrContext.rendered = () => {
|
||||
// Add the state from the vuex store
|
||||
ssrContext.nuxt.state = store.state
|
||||
}
|
||||
}
|
||||
|
||||
const renderErrorPage = async () => {
|
||||
// Don't server-render the page in static target
|
||||
if (ssrContext.target === 'static') {
|
||||
ssrContext.nuxt.serverRendered = false
|
||||
}
|
||||
|
||||
// Load layout for error page
|
||||
const layout = (NuxtError.options || NuxtError).layout
|
||||
const errLayout = typeof layout === 'function' ? layout.call(NuxtError, app.context) : layout
|
||||
ssrContext.nuxt.layout = errLayout || 'default'
|
||||
await _app.loadLayout(errLayout)
|
||||
_app.setLayout(errLayout)
|
||||
|
||||
await beforeRender()
|
||||
return _app
|
||||
}
|
||||
const render404Page = () => {
|
||||
app.context.error({ statusCode: 404, path: ssrContext.url, message: 'This page could not be found' })
|
||||
return renderErrorPage()
|
||||
}
|
||||
|
||||
const s = Date.now()
|
||||
|
||||
// Components are already resolved by setContext -> getRouteData (app/utils.js)
|
||||
const Components = getMatchedComponents(app.context.route)
|
||||
|
||||
/*
|
||||
** Dispatch store nuxtServerInit
|
||||
*/
|
||||
if (store._actions && store._actions.nuxtServerInit) {
|
||||
try {
|
||||
await store.dispatch('nuxtServerInit', app.context)
|
||||
} catch (err) {
|
||||
console.debug('Error occurred when calling nuxtServerInit: ', err.message)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
// ...If there is a redirect or an error, stop the process
|
||||
if (ssrContext.redirected) {
|
||||
return noopApp()
|
||||
}
|
||||
if (ssrContext.nuxt.error) {
|
||||
return renderErrorPage()
|
||||
}
|
||||
|
||||
/*
|
||||
** Call global middleware (nuxt.config.js)
|
||||
*/
|
||||
let midd = ["i18n"]
|
||||
midd = midd.map((name) => {
|
||||
if (typeof name === 'function') {
|
||||
return name
|
||||
}
|
||||
if (typeof middleware[name] !== 'function') {
|
||||
app.context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
|
||||
}
|
||||
return middleware[name]
|
||||
})
|
||||
await middlewareSeries(midd, app.context)
|
||||
// ...If there is a redirect or an error, stop the process
|
||||
if (ssrContext.redirected) {
|
||||
return noopApp()
|
||||
}
|
||||
if (ssrContext.nuxt.error) {
|
||||
return renderErrorPage()
|
||||
}
|
||||
|
||||
/*
|
||||
** Set layout
|
||||
*/
|
||||
let layout = Components.length ? Components[0].options.layout : NuxtError.layout
|
||||
if (typeof layout === 'function') {
|
||||
layout = layout(app.context)
|
||||
}
|
||||
await _app.loadLayout(layout)
|
||||
if (ssrContext.nuxt.error) {
|
||||
return renderErrorPage()
|
||||
}
|
||||
layout = _app.setLayout(layout)
|
||||
ssrContext.nuxt.layout = _app.layoutName
|
||||
|
||||
/*
|
||||
** Call middleware (layout + pages)
|
||||
*/
|
||||
midd = []
|
||||
|
||||
layout = sanitizeComponent(layout)
|
||||
if (layout.options.middleware) {
|
||||
midd = midd.concat(layout.options.middleware)
|
||||
}
|
||||
|
||||
Components.forEach((Component) => {
|
||||
if (Component.options.middleware) {
|
||||
midd = midd.concat(Component.options.middleware)
|
||||
}
|
||||
})
|
||||
midd = midd.map((name) => {
|
||||
if (typeof name === 'function') {
|
||||
return name
|
||||
}
|
||||
if (typeof middleware[name] !== 'function') {
|
||||
app.context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
|
||||
}
|
||||
return middleware[name]
|
||||
})
|
||||
await middlewareSeries(midd, app.context)
|
||||
// ...If there is a redirect or an error, stop the process
|
||||
if (ssrContext.redirected) {
|
||||
return noopApp()
|
||||
}
|
||||
if (ssrContext.nuxt.error) {
|
||||
return renderErrorPage()
|
||||
}
|
||||
|
||||
/*
|
||||
** Call .validate()
|
||||
*/
|
||||
let isValid = true
|
||||
try {
|
||||
for (const Component of Components) {
|
||||
if (typeof Component.options.validate !== 'function') {
|
||||
continue
|
||||
}
|
||||
|
||||
isValid = await Component.options.validate(app.context)
|
||||
|
||||
if (!isValid) {
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (validationError) {
|
||||
// ...If .validate() threw an error
|
||||
app.context.error({
|
||||
statusCode: validationError.statusCode || '500',
|
||||
message: validationError.message
|
||||
})
|
||||
return renderErrorPage()
|
||||
}
|
||||
|
||||
// ...If .validate() returned false
|
||||
if (!isValid) {
|
||||
// Render a 404 error page
|
||||
return render404Page()
|
||||
}
|
||||
|
||||
// If no Components found, returns 404
|
||||
if (!Components.length) {
|
||||
return render404Page()
|
||||
}
|
||||
|
||||
// Call asyncData & fetch hooks on components matched by the route.
|
||||
const asyncDatas = await Promise.all(Components.map((Component) => {
|
||||
const promises = []
|
||||
|
||||
// Call asyncData(context)
|
||||
if (Component.options.asyncData && typeof Component.options.asyncData === 'function') {
|
||||
const promise = promisify(Component.options.asyncData, app.context)
|
||||
promise.then((asyncDataResult) => {
|
||||
ssrContext.asyncData[Component.cid] = asyncDataResult
|
||||
applyAsyncData(Component)
|
||||
return asyncDataResult
|
||||
})
|
||||
promises.push(promise)
|
||||
} else {
|
||||
promises.push(null)
|
||||
}
|
||||
|
||||
// Call fetch(context)
|
||||
if (Component.options.fetch && Component.options.fetch.length) {
|
||||
promises.push(Component.options.fetch(app.context))
|
||||
} else {
|
||||
promises.push(null)
|
||||
}
|
||||
|
||||
return Promise.all(promises)
|
||||
}))
|
||||
|
||||
if (process.env.DEBUG && asyncDatas.length) console.debug('Data fetching ' + ssrContext.url + ': ' + (Date.now() - s) + 'ms')
|
||||
|
||||
// datas are the first row of each
|
||||
ssrContext.nuxt.data = asyncDatas.map(r => r[0] || {})
|
||||
|
||||
// ...If there is a redirect or an error, stop the process
|
||||
if (ssrContext.redirected) {
|
||||
return noopApp()
|
||||
}
|
||||
if (ssrContext.nuxt.error) {
|
||||
return renderErrorPage()
|
||||
}
|
||||
|
||||
// Call beforeNuxtRender methods & add store state
|
||||
await beforeRender()
|
||||
|
||||
return _app
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const VUEX_PROPERTIES = ['state', 'getters', 'actions', 'mutations']
|
||||
|
||||
let store = {};
|
||||
|
||||
(function updateModules () {
|
||||
store = normalizeRoot(require('../store/index.js'), 'store/index.js')
|
||||
|
||||
// If store is an exported method = classic mode (deprecated)
|
||||
|
||||
if (typeof store === 'function') {
|
||||
return console.warn('Classic mode for store/ is deprecated and will be removed in Nuxt 3.')
|
||||
}
|
||||
|
||||
// Enforce store modules
|
||||
store.modules = store.modules || {}
|
||||
|
||||
resolveStoreModules(require('../store/action-menu.js'), 'action-menu.js')
|
||||
resolveStoreModules(require('../store/auth.js'), 'auth.js')
|
||||
resolveStoreModules(require('../store/aws.js'), 'aws.js')
|
||||
resolveStoreModules(require('../store/catalog.js'), 'catalog.js')
|
||||
resolveStoreModules(require('../store/digitalocean.js'), 'digitalocean.js')
|
||||
resolveStoreModules(require('../store/features.js'), 'features.js')
|
||||
resolveStoreModules(require('../store/github.js'), 'github.js')
|
||||
resolveStoreModules(require('../store/growl.js'), 'growl.js')
|
||||
resolveStoreModules(require('../store/i18n.js'), 'i18n.js')
|
||||
resolveStoreModules(require('../store/linode.js'), 'linode.js')
|
||||
resolveStoreModules(require('../store/plugins.js'), 'plugins.js')
|
||||
resolveStoreModules(require('../store/pnap.js'), 'pnap.js')
|
||||
resolveStoreModules(require('../store/prefs.js'), 'prefs.js')
|
||||
resolveStoreModules(require('../store/resource-fetch.js'), 'resource-fetch.js')
|
||||
resolveStoreModules(require('../store/type-map.js'), 'type-map.js')
|
||||
resolveStoreModules(require('../store/uiplugins.ts'), 'uiplugins.ts')
|
||||
resolveStoreModules(require('../store/wm.js'), 'wm.js')
|
||||
|
||||
// If the environment supports hot reloading...
|
||||
|
||||
if (process.client && module.hot) {
|
||||
// Whenever any Vuex module is updated...
|
||||
module.hot.accept([
|
||||
'../store/action-menu.js',
|
||||
'../store/auth.js',
|
||||
'../store/aws.js',
|
||||
'../store/catalog.js',
|
||||
'../store/digitalocean.js',
|
||||
'../store/features.js',
|
||||
'../store/github.js',
|
||||
'../store/growl.js',
|
||||
'../store/i18n.js',
|
||||
'../store/index.js',
|
||||
'../store/linode.js',
|
||||
'../store/plugins.js',
|
||||
'../store/pnap.js',
|
||||
'../store/prefs.js',
|
||||
'../store/resource-fetch.js',
|
||||
'../store/type-map.js',
|
||||
'../store/uiplugins.ts',
|
||||
'../store/wm.js',
|
||||
], () => {
|
||||
// Update `root.modules` with the latest definitions.
|
||||
updateModules()
|
||||
// Trigger a hot update in the store.
|
||||
window.$nuxt.$store.hotUpdate(store)
|
||||
})
|
||||
}
|
||||
})()
|
||||
|
||||
// createStore
|
||||
export const createStore = store instanceof Function ? store : () => {
|
||||
return new Vuex.Store(Object.assign({
|
||||
strict: (process.env.NODE_ENV !== 'production')
|
||||
}, store))
|
||||
}
|
||||
|
||||
function normalizeRoot (moduleData, filePath) {
|
||||
moduleData = moduleData.default || moduleData
|
||||
|
||||
if (moduleData.commit) {
|
||||
throw new Error(`[nuxt] ${filePath} should export a method that returns a Vuex instance.`)
|
||||
}
|
||||
|
||||
if (typeof moduleData !== 'function') {
|
||||
// Avoid TypeError: setting a property that has only a getter when overwriting top level keys
|
||||
moduleData = Object.assign({}, moduleData)
|
||||
}
|
||||
return normalizeModule(moduleData, filePath)
|
||||
}
|
||||
|
||||
function normalizeModule (moduleData, filePath) {
|
||||
if (moduleData.state && typeof moduleData.state !== 'function') {
|
||||
console.warn(`'state' should be a method that returns an object in ${filePath}`)
|
||||
|
||||
const state = Object.assign({}, moduleData.state)
|
||||
// Avoid TypeError: setting a property that has only a getter when overwriting top level keys
|
||||
moduleData = Object.assign({}, moduleData, { state: () => state })
|
||||
}
|
||||
return moduleData
|
||||
}
|
||||
|
||||
function resolveStoreModules (moduleData, filename) {
|
||||
moduleData = moduleData.default || moduleData
|
||||
// Remove store src + extension (./foo/index.js -> foo/index)
|
||||
const namespace = filename.replace(/\.(js|mjs|ts)$/, '')
|
||||
const namespaces = namespace.split('/')
|
||||
let moduleName = namespaces[namespaces.length - 1]
|
||||
const filePath = `store/${filename}`
|
||||
|
||||
moduleData = moduleName === 'state'
|
||||
? normalizeState(moduleData, filePath)
|
||||
: normalizeModule(moduleData, filePath)
|
||||
|
||||
// If src is a known Vuex property
|
||||
if (VUEX_PROPERTIES.includes(moduleName)) {
|
||||
const property = moduleName
|
||||
const propertyStoreModule = getStoreModule(store, namespaces, { isProperty: true })
|
||||
|
||||
// Replace state since it's a function
|
||||
mergeProperty(propertyStoreModule, moduleData, property)
|
||||
return
|
||||
}
|
||||
|
||||
// If file is foo/index.js, it should be saved as foo
|
||||
const isIndexModule = (moduleName === 'index')
|
||||
if (isIndexModule) {
|
||||
namespaces.pop()
|
||||
moduleName = namespaces[namespaces.length - 1]
|
||||
}
|
||||
|
||||
const storeModule = getStoreModule(store, namespaces)
|
||||
|
||||
for (const property of VUEX_PROPERTIES) {
|
||||
mergeProperty(storeModule, moduleData[property], property)
|
||||
}
|
||||
|
||||
if (moduleData.namespaced === false) {
|
||||
delete storeModule.namespaced
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeState (moduleData, filePath) {
|
||||
if (typeof moduleData !== 'function') {
|
||||
console.warn(`${filePath} should export a method that returns an object`)
|
||||
const state = Object.assign({}, moduleData)
|
||||
return () => state
|
||||
}
|
||||
return normalizeModule(moduleData, filePath)
|
||||
}
|
||||
|
||||
function getStoreModule (storeModule, namespaces, { isProperty = false } = {}) {
|
||||
// If ./mutations.js
|
||||
if (!namespaces.length || (isProperty && namespaces.length === 1)) {
|
||||
return storeModule
|
||||
}
|
||||
|
||||
const namespace = namespaces.shift()
|
||||
|
||||
storeModule.modules[namespace] = storeModule.modules[namespace] || {}
|
||||
storeModule.modules[namespace].namespaced = true
|
||||
storeModule.modules[namespace].modules = storeModule.modules[namespace].modules || {}
|
||||
|
||||
return getStoreModule(storeModule.modules[namespace], namespaces, { isProperty })
|
||||
}
|
||||
|
||||
function mergeProperty (storeModule, moduleData, property) {
|
||||
if (!moduleData) {
|
||||
return
|
||||
}
|
||||
|
||||
if (property === 'state') {
|
||||
storeModule.state = moduleData || storeModule.state
|
||||
} else {
|
||||
storeModule[property] = Object.assign({}, storeModule[property], moduleData)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,630 @@
|
|||
import Vue from 'vue'
|
||||
import { isSamePath as _isSamePath, joinURL, normalizeURL, withQuery, withoutTrailingSlash } from 'ufo'
|
||||
|
||||
// window.{{globals.loadedCallback}} hook
|
||||
// Useful for jsdom testing or plugins (https://github.com/tmpvar/jsdom#dealing-with-asynchronous-script-loading)
|
||||
if (process.client) {
|
||||
window.onNuxtReadyCbs = []
|
||||
window.onNuxtReady = (cb) => {
|
||||
window.onNuxtReadyCbs.push(cb)
|
||||
}
|
||||
}
|
||||
|
||||
export function createGetCounter (counterObject, defaultKey = '') {
|
||||
return function getCounter (id = defaultKey) {
|
||||
if (counterObject[id] === undefined) {
|
||||
counterObject[id] = 0
|
||||
}
|
||||
return counterObject[id]++
|
||||
}
|
||||
}
|
||||
|
||||
export function empty () {}
|
||||
|
||||
export function globalHandleError (error) {
|
||||
if (Vue.config.errorHandler) {
|
||||
Vue.config.errorHandler(error)
|
||||
}
|
||||
}
|
||||
|
||||
export function interopDefault (promise) {
|
||||
return promise.then(m => m.default || m)
|
||||
}
|
||||
|
||||
export function hasFetch(vm) {
|
||||
return vm.$options && typeof vm.$options.fetch === 'function' && !vm.$options.fetch.length
|
||||
}
|
||||
export function purifyData(data) {
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
return data
|
||||
}
|
||||
|
||||
return Object.entries(data).filter(
|
||||
([key, value]) => {
|
||||
const valid = !(value instanceof Function) && !(value instanceof Promise)
|
||||
if (!valid) {
|
||||
console.warn(`${key} is not able to be stringified. This will break in a production environment.`)
|
||||
}
|
||||
return valid
|
||||
}
|
||||
).reduce((obj, [key, value]) => {
|
||||
obj[key] = value
|
||||
return obj
|
||||
}, {})
|
||||
}
|
||||
export function getChildrenComponentInstancesUsingFetch(vm, instances = []) {
|
||||
const children = vm.$children || []
|
||||
for (const child of children) {
|
||||
if (child.$fetch) {
|
||||
instances.push(child)
|
||||
continue; // Don't get the children since it will reload the template
|
||||
}
|
||||
if (child.$children) {
|
||||
getChildrenComponentInstancesUsingFetch(child, instances)
|
||||
}
|
||||
}
|
||||
return instances
|
||||
}
|
||||
|
||||
export function applyAsyncData (Component, asyncData) {
|
||||
if (
|
||||
// For SSR, we once all this function without second param to just apply asyncData
|
||||
// Prevent doing this for each SSR request
|
||||
!asyncData && Component.options.__hasNuxtData
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const ComponentData = Component.options._originDataFn || Component.options.data || function () { return {} }
|
||||
Component.options._originDataFn = ComponentData
|
||||
|
||||
Component.options.data = function () {
|
||||
const data = ComponentData.call(this, this)
|
||||
if (this.$ssrContext) {
|
||||
asyncData = this.$ssrContext.asyncData[Component.cid]
|
||||
}
|
||||
return { ...data, ...asyncData }
|
||||
}
|
||||
|
||||
Component.options.__hasNuxtData = true
|
||||
|
||||
if (Component._Ctor && Component._Ctor.options) {
|
||||
Component._Ctor.options.data = Component.options.data
|
||||
}
|
||||
}
|
||||
|
||||
export function sanitizeComponent (Component) {
|
||||
// If Component already sanitized
|
||||
if (Component.options && Component._Ctor === Component) {
|
||||
return Component
|
||||
}
|
||||
if (!Component.options) {
|
||||
Component = Vue.extend(Component) // fix issue #6
|
||||
Component._Ctor = Component
|
||||
} else {
|
||||
Component._Ctor = Component
|
||||
Component.extendOptions = Component.options
|
||||
}
|
||||
// If no component name defined, set file path as name, (also fixes #5703)
|
||||
if (!Component.options.name && Component.options.__file) {
|
||||
Component.options.name = Component.options.__file
|
||||
}
|
||||
return Component
|
||||
}
|
||||
|
||||
export function getMatchedComponents (route, matches = false, prop = 'components') {
|
||||
return Array.prototype.concat.apply([], route.matched.map((m, index) => {
|
||||
return Object.keys(m[prop]).map((key) => {
|
||||
matches && matches.push(index)
|
||||
return m[prop][key]
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
export function getMatchedComponentsInstances (route, matches = false) {
|
||||
return getMatchedComponents(route, matches, 'instances')
|
||||
}
|
||||
|
||||
export function flatMapComponents (route, fn) {
|
||||
return Array.prototype.concat.apply([], route.matched.map((m, index) => {
|
||||
return Object.keys(m.components).reduce((promises, key) => {
|
||||
if (m.components[key]) {
|
||||
promises.push(fn(m.components[key], m.instances[key], m, key, index))
|
||||
} else {
|
||||
delete m.components[key]
|
||||
}
|
||||
return promises
|
||||
}, [])
|
||||
}))
|
||||
}
|
||||
|
||||
export function resolveRouteComponents (route, fn) {
|
||||
return Promise.all(
|
||||
flatMapComponents(route, async (Component, instance, match, key) => {
|
||||
// If component is a function, resolve it
|
||||
if (typeof Component === 'function' && !Component.options) {
|
||||
try {
|
||||
Component = await Component()
|
||||
} catch (error) {
|
||||
// Handle webpack chunk loading errors
|
||||
// This may be due to a new deployment or a network problem
|
||||
if (
|
||||
error &&
|
||||
error.name === 'ChunkLoadError' &&
|
||||
typeof window !== 'undefined' &&
|
||||
window.sessionStorage
|
||||
) {
|
||||
const timeNow = Date.now()
|
||||
const previousReloadTime = parseInt(window.sessionStorage.getItem('nuxt-reload'))
|
||||
|
||||
// check for previous reload time not to reload infinitely
|
||||
if (!previousReloadTime || previousReloadTime + 60000 < timeNow) {
|
||||
window.sessionStorage.setItem('nuxt-reload', timeNow)
|
||||
window.location.reload(true /* skip cache */)
|
||||
}
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
match.components[key] = Component = sanitizeComponent(Component)
|
||||
return typeof fn === 'function' ? fn(Component, instance, match, key) : Component
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export async function getRouteData (route) {
|
||||
if (!route) {
|
||||
return
|
||||
}
|
||||
// Make sure the components are resolved (code-splitting)
|
||||
await resolveRouteComponents(route)
|
||||
// Send back a copy of route with meta based on Component definition
|
||||
return {
|
||||
...route,
|
||||
meta: getMatchedComponents(route).map((Component, index) => {
|
||||
return { ...Component.options.meta, ...(route.matched[index] || {}).meta }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export async function setContext (app, context) {
|
||||
// If context not defined, create it
|
||||
if (!app.context) {
|
||||
app.context = {
|
||||
isStatic: process.static,
|
||||
isDev: true,
|
||||
isHMR: false,
|
||||
app,
|
||||
store: app.store,
|
||||
payload: context.payload,
|
||||
error: context.error,
|
||||
base: app.router.options.base,
|
||||
env: {"commit":"head","version":"0.1.2","dev":true,"pl":1,"perfTest":false,"rancherEnv":"web","api":"http://localhost:8989"}
|
||||
}
|
||||
// Only set once
|
||||
|
||||
if (context.req) {
|
||||
app.context.req = context.req
|
||||
}
|
||||
if (context.res) {
|
||||
app.context.res = context.res
|
||||
}
|
||||
|
||||
if (context.ssrContext) {
|
||||
app.context.ssrContext = context.ssrContext
|
||||
}
|
||||
app.context.redirect = (status, path, query) => {
|
||||
if (!status) {
|
||||
return
|
||||
}
|
||||
app.context._redirected = true
|
||||
// if only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' })
|
||||
let pathType = typeof path
|
||||
if (typeof status !== 'number' && (pathType === 'undefined' || pathType === 'object')) {
|
||||
query = path || {}
|
||||
path = status
|
||||
pathType = typeof path
|
||||
status = 302
|
||||
}
|
||||
if (pathType === 'object') {
|
||||
path = app.router.resolve(path).route.fullPath
|
||||
}
|
||||
// "/absolute/route", "./relative/route" or "../relative/route"
|
||||
if (/(^[.]{1,2}\/)|(^\/(?!\/))/.test(path)) {
|
||||
app.context.next({
|
||||
path,
|
||||
query,
|
||||
status
|
||||
})
|
||||
} else {
|
||||
path = withQuery(path, query)
|
||||
if (process.server) {
|
||||
app.context.next({
|
||||
path,
|
||||
status
|
||||
})
|
||||
}
|
||||
if (process.client) {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Location/replace
|
||||
window.location.replace(path)
|
||||
|
||||
// Throw a redirect error
|
||||
throw new Error('ERR_REDIRECT')
|
||||
}
|
||||
}
|
||||
}
|
||||
if (process.server) {
|
||||
app.context.beforeNuxtRender = fn => context.beforeRenderFns.push(fn)
|
||||
}
|
||||
if (process.client) {
|
||||
app.context.nuxtState = window.__NUXT__
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic keys
|
||||
const [currentRouteData, fromRouteData] = await Promise.all([
|
||||
getRouteData(context.route),
|
||||
getRouteData(context.from)
|
||||
])
|
||||
|
||||
if (context.route) {
|
||||
app.context.route = currentRouteData
|
||||
}
|
||||
|
||||
if (context.from) {
|
||||
app.context.from = fromRouteData
|
||||
}
|
||||
|
||||
app.context.next = context.next
|
||||
app.context._redirected = false
|
||||
app.context._errored = false
|
||||
app.context.isHMR = Boolean(context.isHMR)
|
||||
app.context.params = app.context.route.params || {}
|
||||
app.context.query = app.context.route.query || {}
|
||||
}
|
||||
|
||||
export function middlewareSeries (promises, appContext) {
|
||||
if (!promises.length || appContext._redirected || appContext._errored) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
return promisify(promises[0], appContext)
|
||||
.then(() => {
|
||||
return middlewareSeries(promises.slice(1), appContext)
|
||||
})
|
||||
}
|
||||
|
||||
export function promisify (fn, context) {
|
||||
let promise
|
||||
if (fn.length === 2) {
|
||||
console.warn('Callback-based asyncData, fetch or middleware calls are deprecated. ' +
|
||||
'Please switch to promises or async/await syntax')
|
||||
|
||||
// fn(context, callback)
|
||||
promise = new Promise((resolve) => {
|
||||
fn(context, function (err, data) {
|
||||
if (err) {
|
||||
context.error(err)
|
||||
}
|
||||
data = data || {}
|
||||
resolve(data)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
promise = fn(context)
|
||||
}
|
||||
|
||||
if (promise && promise instanceof Promise && typeof promise.then === 'function') {
|
||||
return promise
|
||||
}
|
||||
return Promise.resolve(promise)
|
||||
}
|
||||
|
||||
// Imported from vue-router
|
||||
export function getLocation (base, mode) {
|
||||
if (mode === 'hash') {
|
||||
return window.location.hash.replace(/^#\//, '')
|
||||
}
|
||||
|
||||
base = decodeURI(base).slice(0, -1) // consideration is base is normalized with trailing slash
|
||||
let path = decodeURI(window.location.pathname)
|
||||
|
||||
if (base && path.startsWith(base)) {
|
||||
path = path.slice(base.length)
|
||||
}
|
||||
|
||||
const fullPath = (path || '/') + window.location.search + window.location.hash
|
||||
|
||||
return normalizeURL(fullPath)
|
||||
}
|
||||
|
||||
// Imported from path-to-regexp
|
||||
|
||||
/**
|
||||
* Compile a string to a template function for the path.
|
||||
*
|
||||
* @param {string} str
|
||||
* @param {Object=} options
|
||||
* @return {!function(Object=, Object=)}
|
||||
*/
|
||||
export function compile (str, options) {
|
||||
return tokensToFunction(parse(str, options), options)
|
||||
}
|
||||
|
||||
export function getQueryDiff (toQuery, fromQuery) {
|
||||
const diff = {}
|
||||
const queries = { ...toQuery, ...fromQuery }
|
||||
for (const k in queries) {
|
||||
if (String(toQuery[k]) !== String(fromQuery[k])) {
|
||||
diff[k] = true
|
||||
}
|
||||
}
|
||||
return diff
|
||||
}
|
||||
|
||||
export function normalizeError (err) {
|
||||
let message
|
||||
if (!(err.message || typeof err === 'string')) {
|
||||
try {
|
||||
message = JSON.stringify(err, null, 2)
|
||||
} catch (e) {
|
||||
message = `[${err.constructor.name}]`
|
||||
}
|
||||
} else {
|
||||
message = err.message || err
|
||||
}
|
||||
return {
|
||||
...err,
|
||||
message,
|
||||
statusCode: (err.statusCode || err.status || (err.response && err.response.status) || 500)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main path matching regexp utility.
|
||||
*
|
||||
* @type {RegExp}
|
||||
*/
|
||||
const PATH_REGEXP = new RegExp([
|
||||
// Match escaped characters that would otherwise appear in future matches.
|
||||
// This allows the user to escape special characters that won't transform.
|
||||
'(\\\\.)',
|
||||
// Match Express-style parameters and un-named parameters with a prefix
|
||||
// and optional suffixes. Matches appear as:
|
||||
//
|
||||
// "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
|
||||
// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
|
||||
// "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
|
||||
'([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
|
||||
].join('|'), 'g')
|
||||
|
||||
/**
|
||||
* Parse a string for the raw tokens.
|
||||
*
|
||||
* @param {string} str
|
||||
* @param {Object=} options
|
||||
* @return {!Array}
|
||||
*/
|
||||
function parse (str, options) {
|
||||
const tokens = []
|
||||
let key = 0
|
||||
let index = 0
|
||||
let path = ''
|
||||
const defaultDelimiter = (options && options.delimiter) || '/'
|
||||
let res
|
||||
|
||||
while ((res = PATH_REGEXP.exec(str)) != null) {
|
||||
const m = res[0]
|
||||
const escaped = res[1]
|
||||
const offset = res.index
|
||||
path += str.slice(index, offset)
|
||||
index = offset + m.length
|
||||
|
||||
// Ignore already escaped sequences.
|
||||
if (escaped) {
|
||||
path += escaped[1]
|
||||
continue
|
||||
}
|
||||
|
||||
const next = str[index]
|
||||
const prefix = res[2]
|
||||
const name = res[3]
|
||||
const capture = res[4]
|
||||
const group = res[5]
|
||||
const modifier = res[6]
|
||||
const asterisk = res[7]
|
||||
|
||||
// Push the current path onto the tokens.
|
||||
if (path) {
|
||||
tokens.push(path)
|
||||
path = ''
|
||||
}
|
||||
|
||||
const partial = prefix != null && next != null && next !== prefix
|
||||
const repeat = modifier === '+' || modifier === '*'
|
||||
const optional = modifier === '?' || modifier === '*'
|
||||
const delimiter = res[2] || defaultDelimiter
|
||||
const pattern = capture || group
|
||||
|
||||
tokens.push({
|
||||
name: name || key++,
|
||||
prefix: prefix || '',
|
||||
delimiter,
|
||||
optional,
|
||||
repeat,
|
||||
partial,
|
||||
asterisk: Boolean(asterisk),
|
||||
pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
|
||||
})
|
||||
}
|
||||
|
||||
// Match any characters still remaining.
|
||||
if (index < str.length) {
|
||||
path += str.substr(index)
|
||||
}
|
||||
|
||||
// If the path exists, push it onto the end.
|
||||
if (path) {
|
||||
tokens.push(path)
|
||||
}
|
||||
|
||||
return tokens
|
||||
}
|
||||
|
||||
/**
|
||||
* Prettier encoding of URI path segments.
|
||||
*
|
||||
* @param {string}
|
||||
* @return {string}
|
||||
*/
|
||||
function encodeURIComponentPretty (str, slashAllowed) {
|
||||
const re = slashAllowed ? /[?#]/g : /[/?#]/g
|
||||
return encodeURI(str).replace(re, (c) => {
|
||||
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
|
||||
*
|
||||
* @param {string}
|
||||
* @return {string}
|
||||
*/
|
||||
function encodeAsterisk (str) {
|
||||
return encodeURIComponentPretty(str, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a regular expression string.
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
*/
|
||||
function escapeString (str) {
|
||||
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1')
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape the capturing group by escaping special characters and meaning.
|
||||
*
|
||||
* @param {string} group
|
||||
* @return {string}
|
||||
*/
|
||||
function escapeGroup (group) {
|
||||
return group.replace(/([=!:$/()])/g, '\\$1')
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose a method for transforming tokens into the path function.
|
||||
*/
|
||||
function tokensToFunction (tokens, options) {
|
||||
// Compile all the tokens into regexps.
|
||||
const matches = new Array(tokens.length)
|
||||
|
||||
// Compile all the patterns before compilation.
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
if (typeof tokens[i] === 'object') {
|
||||
matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$', flags(options))
|
||||
}
|
||||
}
|
||||
|
||||
return function (obj, opts) {
|
||||
let path = ''
|
||||
const data = obj || {}
|
||||
const options = opts || {}
|
||||
const encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent
|
||||
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
const token = tokens[i]
|
||||
|
||||
if (typeof token === 'string') {
|
||||
path += token
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
const value = data[token.name || 'pathMatch']
|
||||
let segment
|
||||
|
||||
if (value == null) {
|
||||
if (token.optional) {
|
||||
// Prepend partial segment prefixes.
|
||||
if (token.partial) {
|
||||
path += token.prefix
|
||||
}
|
||||
|
||||
continue
|
||||
} else {
|
||||
throw new TypeError('Expected "' + token.name + '" to be defined')
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
if (!token.repeat) {
|
||||
throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
|
||||
}
|
||||
|
||||
if (value.length === 0) {
|
||||
if (token.optional) {
|
||||
continue
|
||||
} else {
|
||||
throw new TypeError('Expected "' + token.name + '" to not be empty')
|
||||
}
|
||||
}
|
||||
|
||||
for (let j = 0; j < value.length; j++) {
|
||||
segment = encode(value[j])
|
||||
|
||||
if (!matches[i].test(segment)) {
|
||||
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
|
||||
}
|
||||
|
||||
path += (j === 0 ? token.prefix : token.delimiter) + segment
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
segment = token.asterisk ? encodeAsterisk(value) : encode(value)
|
||||
|
||||
if (!matches[i].test(segment)) {
|
||||
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
|
||||
}
|
||||
|
||||
path += token.prefix + segment
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the flags for a regexp from the options.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @return {string}
|
||||
*/
|
||||
function flags (options) {
|
||||
return options && options.sensitive ? '' : 'i'
|
||||
}
|
||||
|
||||
export function addLifecycleHook(vm, hook, fn) {
|
||||
if (!vm.$options[hook]) {
|
||||
vm.$options[hook] = []
|
||||
}
|
||||
if (!vm.$options[hook].includes(fn)) {
|
||||
vm.$options[hook].push(fn)
|
||||
}
|
||||
}
|
||||
|
||||
export const urlJoin = joinURL
|
||||
|
||||
export const stripTrailingSlash = withoutTrailingSlash
|
||||
|
||||
export const isSamePath = _isSamePath
|
||||
|
||||
export function setScrollRestoration (newVal) {
|
||||
try {
|
||||
window.history.scrollRestoration = newVal;
|
||||
} catch(e) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html {{ HTML_ATTRS }}>
|
||||
<head {{ HEAD_ATTRS }}>
|
||||
{{ HEAD }}
|
||||
</head>
|
||||
<body {{ BODY_ATTRS }}>
|
||||
{{ APP }}
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Server error</title>
|
||||
<meta charset="utf-8">
|
||||
<meta content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name=viewport>
|
||||
<style>
|
||||
.__nuxt-error-page{padding: 1rem;background:#f7f8fb;color:#47494e;text-align:center;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;font-family:sans-serif;font-weight:100!important;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;position:absolute;top:0;left:0;right:0;bottom:0}.__nuxt-error-page .error{max-width:450px}.__nuxt-error-page .title{font-size:24px;font-size:1.5rem;margin-top:15px;color:#47494e;margin-bottom:8px}.__nuxt-error-page .description{color:#7f828b;line-height:21px;margin-bottom:10px}.__nuxt-error-page a{color:#7f828b!important;text-decoration:none}.__nuxt-error-page .logo{position:fixed;left:12px;bottom:12px}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="__nuxt-error-page">
|
||||
<div class="error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90" fill="#DBE1EC" viewBox="0 0 48 48"><path d="M22 30h4v4h-4zm0-16h4v12h-4zm1.99-10C12.94 4 4 12.95 4 24s8.94 20 19.99 20S44 35.05 44 24 35.04 4 23.99 4zM24 40c-8.84 0-16-7.16-16-16S15.16 8 24 8s16 7.16 16 16-7.16 16-16 16z"/></svg>
|
||||
<div class="title">Server error</div>
|
||||
<div class="description">{{ message }}</div>
|
||||
</div>
|
||||
<div class="logo">
|
||||
<a href="https://nuxtjs.org" target="_blank" rel="noopener">Nuxt</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -16,15 +16,11 @@
|
|||
"clean": "./scripts/clean",
|
||||
"lint": "./node_modules/.bin/eslint --max-warnings 0 --ext .ts,.js,.vue .",
|
||||
"test": "./node_modules/.bin/nyc ava --serial --verbose",
|
||||
"nuxt": "./node_modules/.bin/nuxt",
|
||||
"dev": "./node_modules/.bin/nuxt dev",
|
||||
"mem-dev": "node --max-old-space-size=8192 ./node_modules/.bin/nuxt dev",
|
||||
"dev": "./node_modules/.bin/vue-cli-service dev",
|
||||
"docker-dev": "docker run --rm --name dashboard-dev -p 8005:8005 -e API=$API -v $(pwd):/src -v dashboard_node:/src/node_modules rancher/dashboard:dev",
|
||||
"build": "./node_modules/.bin/nuxt build --devtools",
|
||||
"analyze": "./node_modules/.bin/nuxt build --analyze",
|
||||
"start": "./node_modules/.bin/nuxt start",
|
||||
"generate": "./node_modules/.bin/nuxt generate",
|
||||
"dev-debug": "node --inspect ./node_modules/.bin/nuxt",
|
||||
"build": "./node_modules/.bin/vue-cli-service build",
|
||||
"analyze": "./node_modules/.bin/vue-cli-service build --report",
|
||||
"start": "./node_modules/.bin/vue-cli-service start",
|
||||
"cy:run": "cypress run",
|
||||
"cy:open": "cypress open",
|
||||
"e2e:pre": "NODE_ENV=dev yarn build",
|
||||
|
|
@ -41,7 +37,6 @@
|
|||
"@innologica/vue-dropdown-menu": "0.1.3",
|
||||
"@novnc/novnc": "1.2.0",
|
||||
"@nuxt/types": "2.14.6",
|
||||
"@nuxt/typescript-build": "2.1.0",
|
||||
"@nuxtjs/axios": "5.12.0",
|
||||
"@nuxtjs/eslint-config-typescript": "6.0.1",
|
||||
"@nuxtjs/eslint-module": "1.2.0",
|
||||
|
|
@ -52,8 +47,6 @@
|
|||
"@types/node": "16.4.3",
|
||||
"@typescript-eslint/eslint-plugin": "4.33.0",
|
||||
"@typescript-eslint/parser": "4.33.0",
|
||||
"@vue/cli-plugin-babel": "4.5.15",
|
||||
"@vue/cli-plugin-typescript": "4.5.15",
|
||||
"@vue/cli-service": "4.5.15",
|
||||
"@vue/test-utils": "1.2.1",
|
||||
"@vue/vue2-jest": "27.0.0",
|
||||
|
|
@ -157,5 +150,8 @@
|
|||
".js",
|
||||
".vue"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli": "4.5.15"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -495,7 +495,7 @@ export default {
|
|||
}
|
||||
|
||||
.landscape {
|
||||
background-image: url('~shell/assets/images/pl/login-landscape.svg');
|
||||
background-image: url('~@shell/assets/images/pl/login-landscape.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ const sharedActions = {
|
|||
msg.selector = selector;
|
||||
}
|
||||
|
||||
const worker = this.$workers[getters.storeName] || {};
|
||||
const worker = this.$workers?.[getters.storeName] || {};
|
||||
|
||||
if (worker.mode === 'advanced') {
|
||||
if ( force ) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/public/favicon.png">
|
||||
<title>Rancher</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app">
|
||||
<script>
|
||||
(() => {
|
||||
const isDark = document.cookie.includes('R_PCS=dark');
|
||||
const color = isDark ? '#1b1c21' : '#FFF';
|
||||
const style = document.createElement('style');
|
||||
style.innerHTML = ':root { --loading-bg-color: ' + color + ';}';
|
||||
document.getElementsByTagName('head')[0].prepend(style);
|
||||
})();
|
||||
</script>
|
||||
<style>
|
||||
.initial-load-spinner-container {
|
||||
align-items: center;
|
||||
background-color: var(--loading-bg-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
.initial-load-spinner {
|
||||
animation: initial-load-animate 1s infinite linear;
|
||||
background-color: var(--loading-bg-color);
|
||||
box-sizing: border-box;
|
||||
border: 5px solid #008ACF;
|
||||
border-radius: 50%;
|
||||
border-top-color: #00B2E2;
|
||||
display: inline-block;
|
||||
height: 80px;
|
||||
margin: 0 auto;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
@keyframes initial-load-animate {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="initial-load-spinner-container">
|
||||
<i class="initial-load-spinner"></i>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -40,6 +40,7 @@ if [ -d "${BASE_DIR}/pkg/${1}" ]; then
|
|||
echo " Package name: ${NAME}"
|
||||
echo " Package version: ${VERSION}"
|
||||
echo " Output formats: ${FORMATS}"
|
||||
echo " Output directory: ${PKG_DIST}"
|
||||
rm -rf ${PKG_DIST}
|
||||
mkdir -p ${PKG_DIST}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,16 +17,16 @@
|
|||
"rootDir": ".",
|
||||
"paths": {
|
||||
"~/*": [
|
||||
"./*"
|
||||
"../*"
|
||||
],
|
||||
"@/*": [
|
||||
"./*"
|
||||
"../*"
|
||||
],
|
||||
"@shell/*": [
|
||||
"./shell/*"
|
||||
"../shell/*"
|
||||
],
|
||||
"@pkg/*": [
|
||||
"./shell/pkg/*"
|
||||
"../shell/pkg/*"
|
||||
]
|
||||
},
|
||||
"typeRoots": [
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"extends": "./tsconfig.default.json",
|
||||
"compilerOptions": {
|
||||
"types": [
|
||||
"@types/node",
|
||||
"@types/jest",
|
||||
"@nuxt/types"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".nuxt",
|
||||
"dist",
|
||||
"dist-pkg",
|
||||
"cypress",
|
||||
"shell/creators",
|
||||
"shell/scripts",
|
||||
"cypress",
|
||||
"./cypress.config.ts",
|
||||
"docusaurus",
|
||||
"script/standalone",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,669 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import serveStatic from 'serve-static';
|
||||
import webpack from 'webpack';
|
||||
import { STANDARD } from './config/private-label';
|
||||
import { generateDynamicTypeImport } from './pkg/auto-import';
|
||||
import CopyWebpackPlugin from 'copy-webpack-plugin';
|
||||
import { createProxyMiddleware } from 'http-proxy-middleware';
|
||||
|
||||
const dev = (process.env.NODE_ENV !== 'production');
|
||||
const devPorts = dev || process.env.DEV_PORTS === 'true';
|
||||
|
||||
// human readable version used on rancher dashboard about page
|
||||
const dashboardVersion = process.env.DASHBOARD_VERSION;
|
||||
|
||||
const prime = process.env.PRIME;
|
||||
|
||||
const pl = process.env.PL || STANDARD;
|
||||
const commit = process.env.COMMIT || 'head';
|
||||
const perfTest = (process.env.PERF_TEST === 'true'); // Enable performance testing when in dev
|
||||
const instrumentCode = (process.env.TEST_INSTRUMENT === 'true'); // Instrument code for code coverage in e2e tests
|
||||
|
||||
let api = process.env.API || 'http://localhost:8989';
|
||||
|
||||
if ( !api.startsWith('http') ) {
|
||||
api = `https://${ api }`;
|
||||
}
|
||||
// ===============================================================================================
|
||||
// Nuxt configuration
|
||||
// ===============================================================================================
|
||||
|
||||
// Expose a function that can be used by an app to provide a nuxt configuration for building an application
|
||||
// This takes the directory of the application as tehfirst argument so that we can derive folder locations
|
||||
// from it, rather than from the location of this file
|
||||
export default function(dir: any, _appConfig: any) {
|
||||
// Paths to the shell folder when it is included as a node dependency
|
||||
let SHELL = 'node_modules/@rancher/shell';
|
||||
let SHELL_ABS = path.join(dir, 'node_modules/@rancher/shell');
|
||||
let COMPONENTS_DIR = path.join(SHELL_ABS, 'rancher-components');
|
||||
|
||||
if (fs.existsSync(SHELL_ABS)) {
|
||||
const stat = fs.lstatSync(SHELL_ABS);
|
||||
|
||||
// If @rancher/shell is a symlink, then use the components folder for it
|
||||
if (stat.isSymbolicLink()) {
|
||||
const REAL_SHELL_ABS = fs.realpathSync(SHELL_ABS); // In case the shell is being linked via 'yarn link'
|
||||
|
||||
COMPONENTS_DIR = path.join(REAL_SHELL_ABS, '..', 'pkg', 'rancher-components', 'src', 'components');
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a local folder named 'shell' then use that rather than the one in node_modules
|
||||
// This will be the case in the main dashboard repository.
|
||||
if (fs.existsSync(path.join(dir, 'shell'))) {
|
||||
SHELL = './shell';
|
||||
SHELL_ABS = path.join(dir, 'shell');
|
||||
COMPONENTS_DIR = path.join(dir, 'pkg', 'rancher-components', 'src', 'components');
|
||||
}
|
||||
|
||||
const babelPlugins: string | (string | object)[] = [
|
||||
// TODO: Browser support
|
||||
// ['@babel/plugin-transform-modules-commonjs'],
|
||||
['@babel/plugin-proposal-private-property-in-object', { loose: true }]
|
||||
];
|
||||
|
||||
if (instrumentCode) {
|
||||
babelPlugins.push('babel-plugin-istanbul');
|
||||
|
||||
console.warn('Instrumenting code for coverage'); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
// ===============================================================================================
|
||||
// Functions for the UI Pluginas
|
||||
// ===============================================================================================
|
||||
|
||||
const appConfig = _appConfig || {};
|
||||
const excludes = appConfig.excludes || [];
|
||||
const autoLoad = appConfig.autoLoad || [];
|
||||
|
||||
const serverMiddleware = [];
|
||||
const autoLoadPackages = [];
|
||||
const watcherIgnores = [
|
||||
/.shell/,
|
||||
/dist-pkg/,
|
||||
/scripts\/standalone/
|
||||
];
|
||||
|
||||
autoLoad.forEach((pkg: any) => {
|
||||
// Need the version number of each file
|
||||
const pkgPackageFile = require(path.join(dir, 'pkg', pkg, 'package.json'));
|
||||
const pkgRef = `${ pkg }-${ pkgPackageFile.version }`;
|
||||
|
||||
autoLoadPackages.push({
|
||||
name: `app-autoload-${ pkgRef }`,
|
||||
content: `/pkg/${ pkgRef }/${ pkgRef }.umd.min.js`
|
||||
});
|
||||
|
||||
// Anything auto-loaded should also be excluded
|
||||
if (!excludes.includes(pkg)) {
|
||||
excludes.push(pkg);
|
||||
}
|
||||
});
|
||||
|
||||
// Find any UI packages in node_modules
|
||||
const NM = path.join(dir, 'node_modules');
|
||||
const pkg = require(path.join(dir, 'package.json'));
|
||||
const nmPackages: any = {};
|
||||
|
||||
if (pkg && pkg.dependencies) {
|
||||
Object.keys(pkg.dependencies).forEach((pkg) => {
|
||||
const f = require(path.join(NM, pkg, 'package.json'));
|
||||
|
||||
// The package.json must have the 'rancher' property to mark it as a UI package
|
||||
if (f.rancher) {
|
||||
const id = `${ f.name }-${ f.version }`;
|
||||
|
||||
nmPackages[id] = f.main;
|
||||
|
||||
// Add server middleware to serve up the files for this UI package
|
||||
serverMiddleware.push({
|
||||
path: `/pkg/${ id }`,
|
||||
handler: serveStatic(path.join(NM, pkg))
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
serverMiddleware.push({
|
||||
path: '/uiplugins-catalog',
|
||||
handler: (req: any, res: any, next: any) => {
|
||||
const p = req.url.split('?');
|
||||
|
||||
try {
|
||||
const proxy = createProxyMiddleware({
|
||||
target: p[1],
|
||||
pathRewrite: { '^.*': p[0] }
|
||||
});
|
||||
|
||||
return proxy(req, res, next);
|
||||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function includePkg(name: any) {
|
||||
if (name.startsWith('.') || name === 'node_modules') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !excludes || (excludes && !excludes.includes(name));
|
||||
}
|
||||
|
||||
excludes.forEach((e: any) => {
|
||||
watcherIgnores.push(new RegExp(`/pkg.${ e }`));
|
||||
});
|
||||
|
||||
// For each package in the pkg folder that is being compiled into the application,
|
||||
// Add in the code to automatically import the types from that package
|
||||
// This imports models, edit, detail, list etc
|
||||
// When built as a UI package, shell/pkg/vue.config.js does the same thing
|
||||
const autoImportTypes: any = {};
|
||||
const VirtualModulesPlugin = require('webpack-virtual-modules');
|
||||
let reqs = '';
|
||||
const pkgFolder = path.relative(dir, './pkg');
|
||||
|
||||
if (fs.existsSync(pkgFolder)) {
|
||||
const items = fs.readdirSync(path.relative(dir, './pkg'));
|
||||
|
||||
// Ignore hidden folders
|
||||
items.filter(name => !name.startsWith('.')).forEach((name) => {
|
||||
const f = require(path.join(dir, 'pkg', name, 'package.json'));
|
||||
|
||||
// Package file must have rancher field to be a plugin
|
||||
if (includePkg(name) && f.rancher) {
|
||||
reqs += `$plugin.initPlugin('${ name }', require(\'~/pkg/${ name }\')); `;
|
||||
}
|
||||
|
||||
// // Serve the code for the UI package in case its used for dynamic loading (but not if the same package was provided in node_modules)
|
||||
// if (!nmPackages[name]) {
|
||||
// const pkgPackageFile = require(path.join(dir, 'pkg', name, 'package.json'));
|
||||
// const pkgRef = `${ name }-${ pkgPackageFile.version }`;
|
||||
|
||||
// serverMiddleware.push({ path: `/pkg/${ pkgRef }`, handler: serveStatic(`${ dir }/dist-pkg/${ pkgRef }`) });
|
||||
// }
|
||||
autoImportTypes[`node_modules/@rancher/auto-import/${ name }`] = generateDynamicTypeImport(`@pkg/${ name }`, path.join(dir, `pkg/${ name }`));
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(nmPackages).forEach((m) => {
|
||||
reqs += `$plugin.loadAsync('${ m }', '/pkg/${ m }/${ nmPackages[m] }');`;
|
||||
});
|
||||
|
||||
// Generate a virtual module '@rancher/dyanmic.js` which imports all of the packages that should be built into the application
|
||||
// This is imported in 'shell/extensions/extension-loader.js` which ensures the all code for plugins to be included is imported in the application
|
||||
const virtualModules = new VirtualModulesPlugin({ 'node_modules/@rancher/dynamic.js': `export default function ($plugin) { ${ reqs } };` });
|
||||
const autoImport = new webpack.NormalModuleReplacementPlugin(/^@rancher\/auto-import$/, (resource: any) => {
|
||||
const ctx = resource.context.split('/');
|
||||
const pkg = ctx[ctx.length - 1];
|
||||
|
||||
resource.request = `@rancher/auto-import/${ pkg }`;
|
||||
});
|
||||
|
||||
// @pkg imports must be resolved to the package that it importing them - this allows a package to use @pkg as an alis
|
||||
// to the root of that particular package
|
||||
const pkgImport = new webpack.NormalModuleReplacementPlugin(/^@pkg/, (resource: any) => {
|
||||
const ctx = resource.context.split('/');
|
||||
// Find 'pkg' folder in the contxt
|
||||
const index = ctx.findIndex((s: any) => s === 'pkg');
|
||||
|
||||
if (index !== -1 && (index + 1) < ctx.length) {
|
||||
const pkg = ctx[index + 1];
|
||||
let p = path.resolve(dir, 'pkg', pkg, resource.request.substr(5));
|
||||
|
||||
if (resource.request.startsWith(`@pkg/${ pkg }`)) {
|
||||
p = path.resolve(dir, 'pkg', resource.request.substr(5));
|
||||
}
|
||||
|
||||
resource.request = p;
|
||||
}
|
||||
});
|
||||
|
||||
// Serve up the dist-pkg folder under /pkg
|
||||
serverMiddleware.push({ path: `/pkg/`, handler: serveStatic(`${ dir }/dist-pkg/`) });
|
||||
// Endpoint to download and unpack a tgz from the local verdaccio rgistry (dev)
|
||||
serverMiddleware.push(path.resolve(dir, SHELL, 'server', 'verdaccio-middleware'));
|
||||
// Add the standard dashboard server middleware after the middleware added to serve up UI packages
|
||||
serverMiddleware.push(path.resolve(dir, SHELL, 'server', 'server-middleware'));
|
||||
|
||||
// ===============================================================================================
|
||||
// Dashboard nuxt configuration
|
||||
// ===============================================================================================
|
||||
|
||||
require('events').EventEmitter.defaultMaxListeners = 20;
|
||||
require('dotenv').config();
|
||||
|
||||
let routerBasePath = '/';
|
||||
let resourceBase = '';
|
||||
let outputDir = 'dist';
|
||||
|
||||
if ( typeof process.env.ROUTER_BASE !== 'undefined' ) {
|
||||
routerBasePath = process.env.ROUTER_BASE;
|
||||
}
|
||||
|
||||
if ( typeof process.env.RESOURCE_BASE !== 'undefined' ) {
|
||||
resourceBase = process.env.RESOURCE_BASE;
|
||||
}
|
||||
|
||||
if ( typeof process.env.OUTPUT_DIR !== 'undefined' ) {
|
||||
outputDir = process.env.OUTPUT_DIR;
|
||||
}
|
||||
|
||||
if ( resourceBase && !resourceBase.endsWith('/') ) {
|
||||
resourceBase += '/';
|
||||
}
|
||||
|
||||
console.log(`Build: ${ dev ? 'Development' : 'Production' }`); // eslint-disable-line no-console
|
||||
|
||||
if ( !dev ) {
|
||||
console.log(`Version: ${ dashboardVersion }`); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if ( !dev ) {
|
||||
console.log(`Version: ${ dashboardVersion }`); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if ( resourceBase ) {
|
||||
console.log(`Resource Base URL: ${ resourceBase }`); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if ( routerBasePath !== '/' ) {
|
||||
console.log(`Router Base Path: ${ routerBasePath }`); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if ( pl !== STANDARD ) {
|
||||
console.log(`PL: ${ pl }`); // eslint-disable-line no-console
|
||||
}
|
||||
const rancherEnv = process.env.RANCHER_ENV || 'web';
|
||||
|
||||
console.log(`API: '${ api }'. Env: '${ rancherEnv }'`); // eslint-disable-line no-console
|
||||
const proxy = {
|
||||
...appConfig.proxies,
|
||||
'/k8s': proxyWsOpts(api), // Straight to a remote cluster (/k8s/clusters/<id>/)
|
||||
'/pp': proxyWsOpts(api), // For (epinio) standalone API
|
||||
'/api': proxyWsOpts(api), // Management k8s API
|
||||
'/apis': proxyWsOpts(api), // Management k8s API
|
||||
'/v1': proxyWsOpts(api), // Management Steve API
|
||||
'/v3': proxyWsOpts(api), // Rancher API
|
||||
'/v3-public': proxyOpts(api), // Rancher Unauthed API
|
||||
'/api-ui': proxyOpts(api), // Browser API UI
|
||||
'/meta': proxyMetaOpts(api), // Browser API UI
|
||||
'/v1-*': proxyOpts(api), // SAML, KDM, etc
|
||||
'/rancherversion': proxyPrimeOpts(api), // Rancher version endpoint
|
||||
// These are for Ember embedding
|
||||
'/c/*/edit': proxyOpts('https://127.0.0.1:8000'), // Can't proxy all of /c because that's used by Vue too
|
||||
'/k/': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/g/': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/n/': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/p/': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/assets': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/translations': proxyOpts('https://127.0.0.1:8000'),
|
||||
'/engines-dist': proxyOpts('https://127.0.0.1:8000'),
|
||||
};
|
||||
|
||||
const config = {
|
||||
// Vue server
|
||||
devServer: {
|
||||
https: (devPorts ? {
|
||||
key: fs.readFileSync(path.resolve(__dirname, 'server/server.key')),
|
||||
cert: fs.readFileSync(path.resolve(__dirname, 'server/server.crt'))
|
||||
} : null),
|
||||
port: (devPorts ? 8005 : 80),
|
||||
host: '0.0.0.0',
|
||||
public: `https://0.0.0.0:${ devPorts ? 8005 : 80 }`,
|
||||
before(app: any, server: any) {
|
||||
const proxies: any = {};
|
||||
|
||||
Object.keys(proxy).forEach((p) => {
|
||||
const px = createProxyMiddleware({
|
||||
...proxy[p],
|
||||
ws: false // We will handle the web socket upgrade
|
||||
});
|
||||
|
||||
proxies[p] = px;
|
||||
app.use(p, px);
|
||||
});
|
||||
|
||||
server.websocketProxies.push({
|
||||
upgrade(req: any, socket: any, head:any) {
|
||||
if (req.url.startsWith('/v1')) {
|
||||
return proxies['/v1'].upgrade(req, socket, head);
|
||||
} else if (req.url.startsWith('/v3')) {
|
||||
return proxies['/v3'].upgrade(req, socket, head);
|
||||
} else if (req.url.startsWith('/k8s/')) {
|
||||
return proxies['/k8s'].upgrade(req, socket, head);
|
||||
} else {
|
||||
console.log(`Unknown Web socket upgrade request for ${ req.url }`); // eslint-disable-line no-console
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
css: {
|
||||
loaderOptions: {
|
||||
sass: {
|
||||
// This is effectively added to the beginning of each style that's imported or included in a vue file. We may want to look into including these in app.scss
|
||||
additionalData: `
|
||||
@use 'sass:math';
|
||||
@import "~shell/assets/styles/base/_variables.scss";
|
||||
@import "~shell/assets/styles/base/_functions.scss";
|
||||
@import "~shell/assets/styles/base/_mixins.scss";
|
||||
`
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
outputDir,
|
||||
|
||||
pages: {
|
||||
index: {
|
||||
entry: path.join(SHELL_ABS, '/nuxt/client.js'),
|
||||
template: path.join(SHELL_ABS, '/public/index.html')
|
||||
}
|
||||
},
|
||||
|
||||
configureWebpack(config: any) {
|
||||
config.resolve.alias['~'] = dir;
|
||||
config.resolve.alias['@'] = dir;
|
||||
config.resolve.alias['~assets'] = path.join(__dirname, 'assets');
|
||||
config.resolve.alias['~shell'] = SHELL_ABS;
|
||||
config.resolve.alias['@shell'] = SHELL_ABS;
|
||||
config.resolve.alias['@pkg'] = path.join(dir, 'pkg');
|
||||
config.resolve.alias['./node_modules'] = path.join(dir, 'node_modules');
|
||||
config.resolve.alias['@components'] = COMPONENTS_DIR;
|
||||
config.resolve.modules.push(__dirname);
|
||||
config.plugins.push(virtualModules);
|
||||
config.plugins.push(autoImport);
|
||||
config.plugins.push(new VirtualModulesPlugin(autoImportTypes));
|
||||
config.plugins.push(pkgImport);
|
||||
// DefinePlugin does string replacement within our code. We may want to consider replacing it with something else. In code we'll see something like
|
||||
// process.env.commit even though process and env aren't even defined objects. This could cause people to be mislead.
|
||||
config.plugins.push(new webpack.DefinePlugin({
|
||||
'process.client': JSON.stringify(true),
|
||||
'process.env.commit': JSON.stringify(commit),
|
||||
'process.env.version': JSON.stringify(dashboardVersion),
|
||||
'process.env.dev': JSON.stringify(dev),
|
||||
'process.env.pl': JSON.stringify(pl),
|
||||
'process.env.perfTest': JSON.stringify(perfTest),
|
||||
'process.env.rancherEnv': JSON.stringify(rancherEnv),
|
||||
'process.env.harvesterPkgUrl': JSON.stringify(process.env.HARVESTER_PKG_URL),
|
||||
'process.env.api': JSON.stringify(api),
|
||||
|
||||
// This is a replacement of the nuxt publicRuntimeConfig
|
||||
'nuxt.publicRuntimeConfig': JSON.stringify({
|
||||
rancherEnv,
|
||||
dashboardVersion
|
||||
}),
|
||||
}));
|
||||
|
||||
// The static assets need to be in the built public folder in order to get served (primarily the favicon for now)
|
||||
config.plugins.push(new CopyWebpackPlugin([{ from: path.join(SHELL_ABS, 'static'), to: 'public' }]));
|
||||
|
||||
config.resolve.extensions.push(...['.tsx', '.ts', '.js', '.vue', '.scss']);
|
||||
config.watchOptions = config.watchOptions || {};
|
||||
config.watchOptions.ignored = watcherIgnores;
|
||||
|
||||
if (dev) {
|
||||
config.devtool = 'cheap-module-source-map';
|
||||
} else {
|
||||
config.devtool = 'source-map';
|
||||
}
|
||||
|
||||
if (resourceBase) {
|
||||
config.output.publicPath = resourceBase;
|
||||
}
|
||||
|
||||
config.resolve.symlinks = false;
|
||||
|
||||
// Ensure we process files in the @rancher/shell folder
|
||||
config.module.rules.forEach((r: any) => {
|
||||
if ('test.js'.match(r.test)) {
|
||||
if (r.exclude) {
|
||||
const orig = r.exclude;
|
||||
|
||||
r.exclude = function(modulePath: string) {
|
||||
if (modulePath.indexOf(SHELL_ABS) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return orig(modulePath);
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Instrument code for tests
|
||||
const babelPlugins: (string | ([] | Object)[])[] = [
|
||||
// TODO: Browser support
|
||||
// ['@babel/plugin-transform-modules-commonjs'],
|
||||
['@babel/plugin-proposal-private-property-in-object', { loose: true }],
|
||||
['@babel/plugin-proposal-class-properties', { loose: true }]
|
||||
];
|
||||
|
||||
if (instrumentCode) {
|
||||
babelPlugins.push('babel-plugin-istanbul');
|
||||
|
||||
console.warn('Instrumenting code for coverage'); // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
const loaders = [
|
||||
// Ensure there is a fallback for browsers that don't support web workers
|
||||
{
|
||||
test: /web-worker.[a-z-]+.js/i,
|
||||
loader: 'worker-loader',
|
||||
options: { inline: 'fallback' },
|
||||
},
|
||||
// Handler for csv files (e.g. ec2 instance data)
|
||||
{
|
||||
test: /\.csv$/i,
|
||||
loader: 'csv-loader',
|
||||
options: {
|
||||
dynamicTyping: true,
|
||||
header: true,
|
||||
skipEmptyLines: true
|
||||
},
|
||||
},
|
||||
// Handler for yaml files (used for i18n files, for example)
|
||||
{
|
||||
test: /\.ya?ml$/i,
|
||||
loader: 'js-yaml-loader',
|
||||
options: { name: '[path][name].[ext]' },
|
||||
},
|
||||
{
|
||||
test: /\.m?[tj]sx?$/,
|
||||
// This excludes no modules except for node_modules/@rancher/... so that plugins can properly compile
|
||||
// when referencing @rancher/shell
|
||||
exclude: /node_modules\/(?!(@rancher)\/).*/,
|
||||
use: [
|
||||
{
|
||||
loader: 'cache-loader',
|
||||
options: {
|
||||
cacheDirectory: 'node_modules/.cache/babel-loader',
|
||||
cacheIdentifier: 'e93f32da'
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
[
|
||||
require.resolve('@nuxt/babel-preset-app'),
|
||||
{
|
||||
corejs: { version: 3 },
|
||||
targets: { browsers: ['last 2 versions'] },
|
||||
modern: true
|
||||
}
|
||||
],
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
plugins: babelPlugins
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'cache-loader',
|
||||
options: {
|
||||
cacheDirectory: 'node_modules/.cache/ts-loader',
|
||||
cacheIdentifier: '3596741e'
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: 'ts-loader',
|
||||
options: {
|
||||
transpileOnly: true,
|
||||
happyPackMode: false,
|
||||
appendTsxSuffixTo: [
|
||||
'\\.vue$'
|
||||
],
|
||||
configFile: path.join(SHELL_ABS, 'tsconfig.json')
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
// Prevent warning in log with the md files in the content folder
|
||||
{
|
||||
test: /\.md$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
name: '[path][name].[ext]',
|
||||
limit: 1,
|
||||
esModule: false
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
// Prevent warning in log with the md files in the content folder
|
||||
{
|
||||
test: /\.md$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'frontmatter-markdown-loader',
|
||||
options: { mode: ['body'] }
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
config.module.rules.push(...loaders);
|
||||
},
|
||||
};
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// ===============================================================================================
|
||||
// Functions for the request proxying used in dev
|
||||
// ===============================================================================================
|
||||
|
||||
function proxyMetaOpts(target: any) {
|
||||
return {
|
||||
target,
|
||||
followRedirects: true,
|
||||
secure: !dev,
|
||||
onProxyReq,
|
||||
onProxyReqWs,
|
||||
onError,
|
||||
onProxyRes,
|
||||
};
|
||||
}
|
||||
|
||||
function proxyOpts(target: any) {
|
||||
return {
|
||||
target,
|
||||
secure: !devPorts,
|
||||
onProxyReq,
|
||||
onProxyReqWs,
|
||||
onError,
|
||||
onProxyRes
|
||||
};
|
||||
}
|
||||
|
||||
// Intercept the /rancherversion API call wnad modify the 'RancherPrime' value
|
||||
// if configured to do so by the environment variable PRIME
|
||||
function proxyPrimeOpts(target: any) {
|
||||
const opts = proxyOpts(target);
|
||||
|
||||
// Don't intercept if the PRIME environment variable is not set
|
||||
if (!prime?.length) {
|
||||
return opts;
|
||||
}
|
||||
|
||||
opts.onProxyRes = (proxyRes, req, res) => {
|
||||
const _end = res.end;
|
||||
let body = '';
|
||||
|
||||
proxyRes.on( 'data', (data: any) => {
|
||||
data = data.toString('utf-8');
|
||||
body += data;
|
||||
});
|
||||
|
||||
res.write = () => {};
|
||||
|
||||
res.end = () => {
|
||||
let output = body;
|
||||
|
||||
try {
|
||||
const out = JSON.parse(body);
|
||||
|
||||
out.RancherPrime = prime;
|
||||
output = JSON.stringify(out);
|
||||
} catch (err) {}
|
||||
|
||||
res.setHeader('content-length', output.length );
|
||||
res.setHeader('content-type', 'application/json' );
|
||||
res.setHeader('transfer-encoding', '');
|
||||
res.setHeader('cache-control', 'no-cache');
|
||||
res.writeHead(proxyRes.statusCode);
|
||||
_end.apply(res, [output]);
|
||||
};
|
||||
};
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
function onProxyRes(proxyRes: any, req: any, res: any) {
|
||||
if (devPorts) {
|
||||
proxyRes.headers['X-Frame-Options'] = 'ALLOWALL';
|
||||
}
|
||||
}
|
||||
|
||||
function proxyWsOpts(target: any) {
|
||||
return {
|
||||
...proxyOpts(target),
|
||||
ws: true,
|
||||
changeOrigin: true,
|
||||
};
|
||||
}
|
||||
|
||||
function onProxyReq(proxyReq: any, req: any) {
|
||||
if (!(proxyReq._currentRequest && proxyReq._currentRequest._headerSent)) {
|
||||
proxyReq.setHeader('x-api-host', req.headers['host']);
|
||||
proxyReq.setHeader('x-forwarded-proto', 'https');
|
||||
}
|
||||
}
|
||||
|
||||
function onProxyReqWs(proxyReq: any, req: any, socket: any, options: any, head: any) {
|
||||
req.headers.origin = options.target.href;
|
||||
proxyReq.setHeader('origin', options.target.href);
|
||||
proxyReq.setHeader('x-api-host', req.headers['host']);
|
||||
proxyReq.setHeader('x-forwarded-proto', 'https');
|
||||
// console.log(proxyReq.getHeaders());
|
||||
|
||||
socket.on('error', (err: any) => {
|
||||
console.error('Proxy WS Error:', err); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
|
||||
function onError(err: any, req: any, res: any) {
|
||||
res.statusCode = 598;
|
||||
console.error('Proxy Error:', err); // eslint-disable-line no-console
|
||||
res.write(JSON.stringify(err));
|
||||
}
|
||||
|
|
@ -1,20 +1,3 @@
|
|||
{
|
||||
"extends": "./tsconfig.default.json",
|
||||
"compilerOptions": {
|
||||
"types": ["@types/node", "@types/jest", "@nuxt/types"]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".nuxt",
|
||||
"dist",
|
||||
"dist-pkg",
|
||||
"cypress",
|
||||
"shell/creators",
|
||||
"shell/scripts",
|
||||
"cypress",
|
||||
"./cypress.config.ts",
|
||||
"docusaurus",
|
||||
"script/standalone",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
"extends": "./shell/tsconfig.json",
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
require('ts-node').register({
|
||||
project: './tsconfig.json',
|
||||
compilerOptions: { module: 'commonjs' },
|
||||
logError: true
|
||||
});
|
||||
|
||||
module.exports = require('./vue.config.ts').default;
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import config from './shell/nuxt.config';
|
||||
|
||||
import config from './shell/vue.config';
|
||||
|
||||
// Excludes the following plugins if there's no .env file.
|
||||
let defaultExcludes = 'epinio, rancher-components, harvester';
|
||||
231
yarn.lock
231
yarn.lock
|
|
@ -1001,7 +1001,12 @@
|
|||
dependencies:
|
||||
"@babel/highlight" "^7.18.6"
|
||||
|
||||
"@babel/compat-data@^7.14.0", "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8", "@babel/compat-data@^7.19.3":
|
||||
"@babel/compat-data@^7.14.0", "@babel/compat-data@^7.19.4":
|
||||
version "7.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.4.tgz#95c86de137bf0317f3a570e1b6e996b427299747"
|
||||
integrity sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==
|
||||
|
||||
"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.18.8", "@babel/compat-data@^7.19.3":
|
||||
version "7.19.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.19.3.tgz#707b939793f867f5a73b2666e6d9a3396eb03151"
|
||||
integrity sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==
|
||||
|
|
@ -1217,6 +1222,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz#181f22d28ebe1b3857fa575f5c290b1aaf659b56"
|
||||
integrity sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==
|
||||
|
||||
"@babel/helper-string-parser@^7.19.4":
|
||||
version "7.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
|
||||
integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
|
||||
|
||||
"@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
|
||||
version "7.19.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
|
||||
|
|
@ -1373,6 +1383,17 @@
|
|||
"@babel/plugin-syntax-object-rest-spread" "^7.8.3"
|
||||
"@babel/plugin-transform-parameters" "^7.18.8"
|
||||
|
||||
"@babel/plugin-proposal-object-rest-spread@^7.19.4":
|
||||
version "7.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz#a8fc86e8180ff57290c91a75d83fe658189b642d"
|
||||
integrity sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.19.4"
|
||||
"@babel/helper-compilation-targets" "^7.19.3"
|
||||
"@babel/helper-plugin-utils" "^7.19.0"
|
||||
"@babel/plugin-syntax-object-rest-spread" "^7.8.3"
|
||||
"@babel/plugin-transform-parameters" "^7.18.8"
|
||||
|
||||
"@babel/plugin-proposal-optional-catch-binding@^7.18.6":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb"
|
||||
|
|
@ -1605,6 +1626,13 @@
|
|||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.18.9"
|
||||
|
||||
"@babel/plugin-transform-block-scoping@^7.19.4":
|
||||
version "7.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz#315d70f68ce64426db379a3d830e7ac30be02e9b"
|
||||
integrity sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.19.0"
|
||||
|
||||
"@babel/plugin-transform-classes@^7.19.0":
|
||||
version "7.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz#0e61ec257fba409c41372175e7c1e606dc79bb20"
|
||||
|
|
@ -1634,6 +1662,13 @@
|
|||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.18.9"
|
||||
|
||||
"@babel/plugin-transform-destructuring@^7.19.4":
|
||||
version "7.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz#46890722687b9b89e1369ad0bd8dc6c5a3b4319d"
|
||||
integrity sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==
|
||||
dependencies:
|
||||
"@babel/helper-plugin-utils" "^7.19.0"
|
||||
|
||||
"@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4":
|
||||
version "7.18.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8"
|
||||
|
|
@ -1849,7 +1884,7 @@
|
|||
"@babel/helper-create-regexp-features-plugin" "^7.18.6"
|
||||
"@babel/helper-plugin-utils" "^7.18.6"
|
||||
|
||||
"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.14.1", "@babel/preset-env@^7.4.4":
|
||||
"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.4.4":
|
||||
version "7.19.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.19.3.tgz#52cd19abaecb3f176a4ff9cc5e15b7bf06bec754"
|
||||
integrity sha512-ziye1OTc9dGFOAXSWKUqQblYHNlBOaDl8wzqf2iKXJAltYiR3hKHUKmkt+S9PppW7RQpq4fFCrwwpIDj/f5P4w==
|
||||
|
|
@ -1930,6 +1965,87 @@
|
|||
core-js-compat "^3.25.1"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/preset-env@^7.14.1":
|
||||
version "7.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.19.4.tgz#4c91ce2e1f994f717efb4237891c3ad2d808c94b"
|
||||
integrity sha512-5QVOTXUdqTCjQuh2GGtdd7YEhoRXBMVGROAtsBeLGIbIz3obCBIfRMT1I3ZKkMgNzwkyCkftDXSSkHxnfVf4qg==
|
||||
dependencies:
|
||||
"@babel/compat-data" "^7.19.4"
|
||||
"@babel/helper-compilation-targets" "^7.19.3"
|
||||
"@babel/helper-plugin-utils" "^7.19.0"
|
||||
"@babel/helper-validator-option" "^7.18.6"
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6"
|
||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9"
|
||||
"@babel/plugin-proposal-async-generator-functions" "^7.19.1"
|
||||
"@babel/plugin-proposal-class-properties" "^7.18.6"
|
||||
"@babel/plugin-proposal-class-static-block" "^7.18.6"
|
||||
"@babel/plugin-proposal-dynamic-import" "^7.18.6"
|
||||
"@babel/plugin-proposal-export-namespace-from" "^7.18.9"
|
||||
"@babel/plugin-proposal-json-strings" "^7.18.6"
|
||||
"@babel/plugin-proposal-logical-assignment-operators" "^7.18.9"
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6"
|
||||
"@babel/plugin-proposal-numeric-separator" "^7.18.6"
|
||||
"@babel/plugin-proposal-object-rest-spread" "^7.19.4"
|
||||
"@babel/plugin-proposal-optional-catch-binding" "^7.18.6"
|
||||
"@babel/plugin-proposal-optional-chaining" "^7.18.9"
|
||||
"@babel/plugin-proposal-private-methods" "^7.18.6"
|
||||
"@babel/plugin-proposal-private-property-in-object" "^7.18.6"
|
||||
"@babel/plugin-proposal-unicode-property-regex" "^7.18.6"
|
||||
"@babel/plugin-syntax-async-generators" "^7.8.4"
|
||||
"@babel/plugin-syntax-class-properties" "^7.12.13"
|
||||
"@babel/plugin-syntax-class-static-block" "^7.14.5"
|
||||
"@babel/plugin-syntax-dynamic-import" "^7.8.3"
|
||||
"@babel/plugin-syntax-export-namespace-from" "^7.8.3"
|
||||
"@babel/plugin-syntax-import-assertions" "^7.18.6"
|
||||
"@babel/plugin-syntax-json-strings" "^7.8.3"
|
||||
"@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
|
||||
"@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
|
||||
"@babel/plugin-syntax-numeric-separator" "^7.10.4"
|
||||
"@babel/plugin-syntax-object-rest-spread" "^7.8.3"
|
||||
"@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
|
||||
"@babel/plugin-syntax-optional-chaining" "^7.8.3"
|
||||
"@babel/plugin-syntax-private-property-in-object" "^7.14.5"
|
||||
"@babel/plugin-syntax-top-level-await" "^7.14.5"
|
||||
"@babel/plugin-transform-arrow-functions" "^7.18.6"
|
||||
"@babel/plugin-transform-async-to-generator" "^7.18.6"
|
||||
"@babel/plugin-transform-block-scoped-functions" "^7.18.6"
|
||||
"@babel/plugin-transform-block-scoping" "^7.19.4"
|
||||
"@babel/plugin-transform-classes" "^7.19.0"
|
||||
"@babel/plugin-transform-computed-properties" "^7.18.9"
|
||||
"@babel/plugin-transform-destructuring" "^7.19.4"
|
||||
"@babel/plugin-transform-dotall-regex" "^7.18.6"
|
||||
"@babel/plugin-transform-duplicate-keys" "^7.18.9"
|
||||
"@babel/plugin-transform-exponentiation-operator" "^7.18.6"
|
||||
"@babel/plugin-transform-for-of" "^7.18.8"
|
||||
"@babel/plugin-transform-function-name" "^7.18.9"
|
||||
"@babel/plugin-transform-literals" "^7.18.9"
|
||||
"@babel/plugin-transform-member-expression-literals" "^7.18.6"
|
||||
"@babel/plugin-transform-modules-amd" "^7.18.6"
|
||||
"@babel/plugin-transform-modules-commonjs" "^7.18.6"
|
||||
"@babel/plugin-transform-modules-systemjs" "^7.19.0"
|
||||
"@babel/plugin-transform-modules-umd" "^7.18.6"
|
||||
"@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1"
|
||||
"@babel/plugin-transform-new-target" "^7.18.6"
|
||||
"@babel/plugin-transform-object-super" "^7.18.6"
|
||||
"@babel/plugin-transform-parameters" "^7.18.8"
|
||||
"@babel/plugin-transform-property-literals" "^7.18.6"
|
||||
"@babel/plugin-transform-regenerator" "^7.18.6"
|
||||
"@babel/plugin-transform-reserved-words" "^7.18.6"
|
||||
"@babel/plugin-transform-shorthand-properties" "^7.18.6"
|
||||
"@babel/plugin-transform-spread" "^7.19.0"
|
||||
"@babel/plugin-transform-sticky-regex" "^7.18.6"
|
||||
"@babel/plugin-transform-template-literals" "^7.18.9"
|
||||
"@babel/plugin-transform-typeof-symbol" "^7.18.9"
|
||||
"@babel/plugin-transform-unicode-escapes" "^7.18.10"
|
||||
"@babel/plugin-transform-unicode-regex" "^7.18.6"
|
||||
"@babel/preset-modules" "^0.1.5"
|
||||
"@babel/types" "^7.19.4"
|
||||
babel-plugin-polyfill-corejs2 "^0.3.3"
|
||||
babel-plugin-polyfill-corejs3 "^0.6.0"
|
||||
babel-plugin-polyfill-regenerator "^0.4.1"
|
||||
core-js-compat "^3.25.1"
|
||||
semver "^6.3.0"
|
||||
|
||||
"@babel/preset-modules@^0.1.5":
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9"
|
||||
|
|
@ -1950,13 +2066,20 @@
|
|||
"@babel/helper-validator-option" "^7.16.7"
|
||||
"@babel/plugin-transform-typescript" "^7.16.7"
|
||||
|
||||
"@babel/runtime@^7.11.0", "@babel/runtime@^7.14.0", "@babel/runtime@^7.15.4", "@babel/runtime@^7.8.4":
|
||||
"@babel/runtime@^7.11.0", "@babel/runtime@^7.15.4", "@babel/runtime@^7.8.4":
|
||||
version "7.19.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.0.tgz#22b11c037b094d27a8a2504ea4dcff00f50e2259"
|
||||
integrity sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.14.0":
|
||||
version "7.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78"
|
||||
integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/template@^7.0.0", "@babel/template@^7.18.10", "@babel/template@^7.3.3":
|
||||
version "7.18.10"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.10.tgz#6f9134835970d1dbf0835c0d100c9f38de0c5e71"
|
||||
|
|
@ -1991,6 +2114,15 @@
|
|||
"@babel/helper-validator-identifier" "^7.19.1"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@babel/types@^7.19.4":
|
||||
version "7.19.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.19.4.tgz#0dd5c91c573a202d600490a35b33246fed8a41c7"
|
||||
integrity sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==
|
||||
dependencies:
|
||||
"@babel/helper-string-parser" "^7.19.4"
|
||||
"@babel/helper-validator-identifier" "^7.19.1"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
"@bcoe/v8-coverage@^0.2.3":
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||
|
|
@ -3122,6 +3254,15 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803"
|
||||
integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow==
|
||||
|
||||
"@types/copy-webpack-plugin@^5.0.3":
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/copy-webpack-plugin/-/copy-webpack-plugin-5.0.3.tgz#9c7ea433ea0abcd0ad1b65a6d11a92c4ad0c691c"
|
||||
integrity sha512-+Iv2lqU4lvAQdXMtQYjT2VuhPcWP+UWdQXfTiz2yfypo2XzEv8WggQcFfK481x1iav3W6FV0bzXBXnlq7+ukhg==
|
||||
dependencies:
|
||||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
"@types/webpack" "^4"
|
||||
|
||||
"@types/eslint-scope@^3.7.3":
|
||||
version "3.7.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16"
|
||||
|
|
@ -3870,6 +4011,15 @@
|
|||
postcss "^8.4.14"
|
||||
source-map "^0.6.1"
|
||||
|
||||
"@vue/compiler-sfc@2.7.11":
|
||||
version "2.7.11"
|
||||
resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-2.7.11.tgz#3b8a60b4145f615a5da023492ee34cc3bb2b545b"
|
||||
integrity sha512-Cf8zvrZWjROgd8yPL8Tc+O3q/Y8ZGM0Y+8blrAvj1RQsVouzUY0oHcx8BA7Hybhb90JRnzeApFrlQGZRUdYpRw==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.18.4"
|
||||
postcss "^8.4.14"
|
||||
source-map "^0.6.1"
|
||||
|
||||
"@vue/component-compiler-utils@^2.3.1":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-2.6.0.tgz#aa46d2a6f7647440b0b8932434d22f12371e543b"
|
||||
|
|
@ -5487,11 +5637,16 @@ caniuse-api@^3.0.0:
|
|||
lodash.memoize "^4.1.2"
|
||||
lodash.uniq "^4.5.0"
|
||||
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001228, caniuse-lite@^1.0.30001400:
|
||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001400:
|
||||
version "1.0.30001412"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001412.tgz#30f67d55a865da43e0aeec003f073ea8764d5d7c"
|
||||
integrity sha512-+TeEIee1gS5bYOiuf+PS/kp2mrXic37Hl66VY6EAfxasIk5fELTktK2oOezYed12H8w7jt3s512PpulQidPjwA==
|
||||
|
||||
caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001228:
|
||||
version "1.0.30001418"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz#5f459215192a024c99e3e3a53aac310fc7cf24e6"
|
||||
integrity sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==
|
||||
|
||||
case-sensitive-paths-webpack-plugin@^2.3.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
|
||||
|
|
@ -5617,7 +5772,12 @@ ci-info@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
|
||||
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
|
||||
|
||||
ci-info@^3.1.1, ci-info@^3.2.0:
|
||||
ci-info@^3.1.1:
|
||||
version "3.5.0"
|
||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.5.0.tgz#bfac2a29263de4c829d806b1ab478e35091e171f"
|
||||
integrity sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==
|
||||
|
||||
ci-info@^3.2.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.4.0.tgz#b28484fd436cbc267900364f096c9dc185efb251"
|
||||
integrity sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==
|
||||
|
|
@ -6142,7 +6302,14 @@ copy-webpack-plugin@^5.1.1:
|
|||
serialize-javascript "^4.0.0"
|
||||
webpack-log "^2.0.0"
|
||||
|
||||
core-js-compat@^3.12.1, core-js-compat@^3.25.1, core-js-compat@^3.6.5:
|
||||
core-js-compat@^3.12.1:
|
||||
version "3.25.5"
|
||||
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.25.5.tgz#0016e8158c904f7b059486639e6e82116eafa7d9"
|
||||
integrity sha512-ovcyhs2DEBUIE0MGEKHP4olCUW/XYte3Vroyxuh38rD1wAO4dHohsovUC4eAOuzFxE6b+RXvBU3UZ9o0YhUTkA==
|
||||
dependencies:
|
||||
browserslist "^4.21.4"
|
||||
|
||||
core-js-compat@^3.25.1, core-js-compat@^3.6.5:
|
||||
version "3.25.3"
|
||||
resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.25.3.tgz#d6a442a03f4eade4555d4e640e6a06151dd95d38"
|
||||
integrity sha512-xVtYpJQ5grszDHEUU9O7XbjjcZ0ccX3LgQsyqSvTnjX97ZqEgn9F5srmrwwwMtbKzDllyFPL+O+2OFMl1lU4TQ==
|
||||
|
|
@ -16267,7 +16434,7 @@ terser@^4.1.2, terser@^4.3.9, terser@^4.6.3:
|
|||
source-map "~0.6.1"
|
||||
source-map-support "~0.5.12"
|
||||
|
||||
terser@^5.10.0, terser@^5.14.1, terser@^5.3.4:
|
||||
terser@^5.10.0, terser@^5.14.1:
|
||||
version "5.15.0"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.0.tgz#e16967894eeba6e1091509ec83f0c60e179f2425"
|
||||
integrity sha512-L1BJiXVmheAQQy+as0oF3Pwtlo4s3Wi1X2zNZ2NxOB4wx9bdS9Vk67XQENLFdLYGCK/Z2di53mTj/hBafR+dTA==
|
||||
|
|
@ -16277,6 +16444,16 @@ terser@^5.10.0, terser@^5.14.1, terser@^5.3.4:
|
|||
commander "^2.20.0"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
terser@^5.3.4:
|
||||
version "5.15.1"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-5.15.1.tgz#8561af6e0fd6d839669c73b92bdd5777d870ed6c"
|
||||
integrity sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==
|
||||
dependencies:
|
||||
"@jridgewell/source-map" "^0.3.2"
|
||||
acorn "^8.5.0"
|
||||
commander "^2.20.0"
|
||||
source-map-support "~0.5.20"
|
||||
|
||||
test-exclude@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
|
||||
|
|
@ -16711,7 +16888,7 @@ uc.micro@^1.0.1, uc.micro@^1.0.5:
|
|||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
|
||||
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
|
||||
|
||||
ufo@^0.7.4:
|
||||
ufo@0.7.11, ufo@^0.7.4:
|
||||
version "0.7.11"
|
||||
resolved "https://registry.yarnpkg.com/ufo/-/ufo-0.7.11.tgz#17defad497981290383c5d26357773431fdbadcb"
|
||||
integrity sha512-IT3q0lPvtkqQ8toHQN/BkOi4VIqoqheqM1FnkNWT9y0G8B3xJhwnoKBu5OHx8zHDOvveQzfKuFowJ0VSARiIDg==
|
||||
|
|
@ -16725,9 +16902,9 @@ uglify-js@3.4.x:
|
|||
source-map "~0.6.1"
|
||||
|
||||
uglify-js@^3.5.1:
|
||||
version "3.17.2"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.2.tgz#f55f668b9a64b213977ae688703b6bbb7ca861c6"
|
||||
integrity sha512-bbxglRjsGQMchfvXZNusUcYgiB9Hx2K4AHYXQy2DITZ9Rd+JzhX7+hoocE5Winr7z2oHvPsekkBwXtigvxevXg==
|
||||
version "3.17.3"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.3.tgz#f0feedf019c4510f164099e8d7e72ff2d7304377"
|
||||
integrity sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==
|
||||
|
||||
un-eval@^1.2.0:
|
||||
version "1.2.0"
|
||||
|
|
@ -16749,7 +16926,7 @@ undefsafe@^2.0.2:
|
|||
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
|
||||
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
|
||||
|
||||
unfetch@^4.2.0:
|
||||
unfetch@4.2.0, unfetch@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be"
|
||||
integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==
|
||||
|
|
@ -17068,7 +17245,7 @@ vm-browserify@^1.0.1:
|
|||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
||||
|
||||
vue-client-only@^2.0.0:
|
||||
vue-client-only@2.1.0, vue-client-only@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-client-only/-/vue-client-only-2.1.0.tgz#1a67a47b8ecacfa86d75830173fffee3bf8a4ee3"
|
||||
integrity sha512-vKl1skEKn8EK9f8P2ZzhRnuaRHLHrlt1sbRmazlvsx6EiC3A8oWF8YCBrMJzoN+W3OnElwIGbVjsx6/xelY1AA==
|
||||
|
|
@ -17131,14 +17308,14 @@ vue-loader@^15.9.2, vue-loader@^15.9.7:
|
|||
vue-hot-reload-api "^2.3.0"
|
||||
vue-style-loader "^4.1.0"
|
||||
|
||||
vue-meta@^2.4.0:
|
||||
vue-meta@2.4.0, vue-meta@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/vue-meta/-/vue-meta-2.4.0.tgz#a419fb4b4135ce965dab32ec641d1989c2ee4845"
|
||||
integrity sha512-XEeZUmlVeODclAjCNpWDnjgw+t3WA6gdzs6ENoIAgwO1J1d5p1tezDhtteLUFwcaQaTtayRrsx7GL6oXp/m2Jw==
|
||||
dependencies:
|
||||
deepmerge "^4.2.2"
|
||||
|
||||
vue-no-ssr@^1.1.1:
|
||||
vue-no-ssr@1.1.1, vue-no-ssr@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-no-ssr/-/vue-no-ssr-1.1.1.tgz#875f3be6fb0ae41568a837f3ac1a80eaa137b998"
|
||||
integrity sha512-ZMjqRpWabMPqPc7gIrG0Nw6vRf1+itwf0Itft7LbMXs2g3Zs/NFmevjZGN1x7K3Q95GmIjWbQZTVerxiBxI+0g==
|
||||
|
|
@ -17148,7 +17325,7 @@ vue-resize@0.4.5, vue-resize@^0.4.5:
|
|||
resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-0.4.5.tgz#4777a23042e3c05620d9cbda01c0b3cc5e32dcea"
|
||||
integrity sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg==
|
||||
|
||||
vue-router@^3.5.1:
|
||||
vue-router@3.6.5, vue-router@^3.5.1:
|
||||
version "3.6.5"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.6.5.tgz#95847d52b9a7e3f1361cb605c8e6441f202afad8"
|
||||
integrity sha512-VYXZQLtjuvKxxcshuRAwjHnciqZVoXAjTjcqBTz4rKc8qih9g9pI3hbDjmqXaHdgL3v8pV6P8Z335XvHzESxLQ==
|
||||
|
|
@ -17173,9 +17350,9 @@ vue-server-renderer@2.6.14:
|
|||
source-map "0.5.6"
|
||||
|
||||
vue-server-renderer@^2.6.12:
|
||||
version "2.7.10"
|
||||
resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.7.10.tgz#e73241c879fcc81de91882ceff135a40f756377c"
|
||||
integrity sha512-hvlnyTZmDmnI7IpQE5YwIwexPi6yJq8eeNTUgLycPX3uhuEobygAQklHoeVREvwNKcET/MnVOtjF4c7t7mw6CQ==
|
||||
version "2.7.11"
|
||||
resolved "https://registry.yarnpkg.com/vue-server-renderer/-/vue-server-renderer-2.7.11.tgz#b27ff9114b3c5a73a64e379a2b195394d202d3f6"
|
||||
integrity sha512-KQe79LrrgvJ2c5PqnhjKta45B64jyOWGOK34VIiujKzsYAN5ynBNYr1E0NaqcobIr/drCnA9S6LZg/rBprfm4w==
|
||||
dependencies:
|
||||
chalk "^4.1.2"
|
||||
hash-sum "^2.0.0"
|
||||
|
|
@ -17211,9 +17388,9 @@ vue-template-compiler@2.6.14:
|
|||
he "^1.1.0"
|
||||
|
||||
vue-template-compiler@^2.6.12, vue-template-compiler@^2.6.14:
|
||||
version "2.7.10"
|
||||
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.10.tgz#9e20f35b2fdccacacf732dd7dedb49bf65f4556b"
|
||||
integrity sha512-QO+8R9YRq1Gudm8ZMdo/lImZLJVUIAM8c07Vp84ojdDAf8HmPJc7XB556PcXV218k2AkKznsRz6xB5uOjAC4EQ==
|
||||
version "2.7.11"
|
||||
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.11.tgz#e18e8e0dcb2647e8d6ff2ede8a3a92e677ff8dea"
|
||||
integrity sha512-17QnXkFiBLOH3gGCA3nWAWpmdlTjOWLyP/2eg5ptgY1OvDBuIDGOW9FZ7ZSKmF1UFyf56mLR3/E1SlCTml1LWQ==
|
||||
dependencies:
|
||||
de-indent "^1.0.2"
|
||||
he "^1.2.0"
|
||||
|
|
@ -17238,7 +17415,7 @@ vue@2.6.14:
|
|||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.14.tgz#e51aa5250250d569a3fbad3a8a5a687d6036e235"
|
||||
integrity sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==
|
||||
|
||||
vue@^2.0.0, vue@^2.6.10, vue@^2.6.12:
|
||||
vue@^2.0.0, vue@^2.6.10:
|
||||
version "2.7.10"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.7.10.tgz#ae516cc6c88e1c424754468844218fdd5e280f40"
|
||||
integrity sha512-HmFC70qarSHPXcKtW8U8fgIkF6JGvjEmDiVInTkKZP0gIlEPhlVlcJJLkdGIDiNkIeA2zJPQTWJUI4iWe+AVfg==
|
||||
|
|
@ -17246,6 +17423,14 @@ vue@^2.0.0, vue@^2.6.10, vue@^2.6.12:
|
|||
"@vue/compiler-sfc" "2.7.10"
|
||||
csstype "^3.1.0"
|
||||
|
||||
vue@^2.6.12:
|
||||
version "2.7.11"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.7.11.tgz#e051d54a131e7094c3ea3a86b2c6ecf25f8d0002"
|
||||
integrity sha512-VPAW5QelT7Tx6UoSw/cwx/jDROOKAK1y/Q0o7HkmVJ1WAypE7w1+UoFa+KsGxy1aYdHPU1oODB3vR6XwSfVhDg==
|
||||
dependencies:
|
||||
"@vue/compiler-sfc" "2.7.11"
|
||||
csstype "^3.1.0"
|
||||
|
||||
vuedraggable@2.24.3:
|
||||
version "2.24.3"
|
||||
resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19"
|
||||
|
|
|
|||
Loading…
Reference in New Issue