mirror of https://github.com/rancher/dashboard.git
Restore vueconfig cleanup with Vue3 migration fixes (#11774)
* Restore vueconfig cleanup with Vue3 migration fixes * Fix aliases for vue * Destructure helper import to avoid duplication * Fix linting issues
This commit is contained in:
parent
6ec92f30e8
commit
3fae34cc92
|
|
@ -4,9 +4,12 @@ const webpack = require('webpack');
|
||||||
const { generateDynamicTypeImport } = require('./pkg/auto-import');
|
const { generateDynamicTypeImport } = require('./pkg/auto-import');
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
const serverMiddlewares = require('./server/server-middleware.js');
|
const serverMiddlewares = require('./server/server-middleware.js');
|
||||||
const configHelper = require('./vue-config-helper.js');
|
const {
|
||||||
|
dev, devPorts, api, proxyWsOpts, proxyOpts, proxyMetaOpts, proxyPrimeOpts
|
||||||
|
} = require('./vue-config-helper.js');
|
||||||
const har = require('./server/har-file');
|
const har = require('./server/har-file');
|
||||||
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
|
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
|
||||||
|
const VirtualModulesPlugin = require('webpack-virtual-modules');
|
||||||
|
|
||||||
// Suppress info level logging messages from http-proxy-middleware
|
// Suppress info level logging messages from http-proxy-middleware
|
||||||
// This hides all of the "[HPM Proxy created] ..." messages
|
// This hides all of the "[HPM Proxy created] ..." messages
|
||||||
|
|
@ -16,33 +19,24 @@ console.info = () => {}; // eslint-disable-line no-console
|
||||||
|
|
||||||
const { createProxyMiddleware } = require('http-proxy-middleware');
|
const { createProxyMiddleware } = require('http-proxy-middleware');
|
||||||
|
|
||||||
|
// TODO: Add explanation of this logic
|
||||||
console.info = oldInfoLogger; // eslint-disable-line no-console
|
console.info = oldInfoLogger; // eslint-disable-line no-console
|
||||||
|
|
||||||
// This is currently hardcoded to avoid importing the TS
|
// This is currently hardcoded to avoid importing the TS
|
||||||
// const { STANDARD } = require('./config/private-label');
|
// const { STANDARD } = require('./config/private-label');
|
||||||
const STANDARD = 1;
|
const STANDARD = 1;
|
||||||
|
|
||||||
const dev = configHelper.dev;
|
|
||||||
const devPorts = configHelper.devPorts;
|
|
||||||
|
|
||||||
// human readable version used on rancher dashboard about page
|
// human readable version used on rancher dashboard about page
|
||||||
const dashboardVersion = process.env.DASHBOARD_VERSION;
|
const dashboardVersion = process.env.DASHBOARD_VERSION;
|
||||||
|
|
||||||
const pl = process.env.PL || STANDARD;
|
const pl = process.env.PL || STANDARD;
|
||||||
const commit = process.env.COMMIT || 'head';
|
const commit = process.env.COMMIT || 'head';
|
||||||
const perfTest = (process.env.PERF_TEST === 'true'); // Enable performance testing when in dev
|
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
|
|
||||||
|
|
||||||
const api = configHelper.api;
|
/**
|
||||||
// ===============================================================================================
|
* Paths to the shell folder when it is included as a node dependency
|
||||||
// Nuxt configuration
|
*/
|
||||||
// ===============================================================================================
|
const getShellPaths = (dir) => {
|
||||||
|
|
||||||
// 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
|
|
||||||
module.exports = function(dir, _appConfig) {
|
|
||||||
// Paths to the shell folder when it is included as a node dependency
|
|
||||||
let SHELL_ABS = path.join(dir, 'node_modules/@rancher/shell');
|
let SHELL_ABS = path.join(dir, 'node_modules/@rancher/shell');
|
||||||
let COMPONENTS_DIR = path.join(SHELL_ABS, 'rancher-components');
|
let COMPONENTS_DIR = path.join(SHELL_ABS, 'rancher-components');
|
||||||
|
|
||||||
|
|
@ -59,274 +53,455 @@ module.exports = function(dir, _appConfig) {
|
||||||
|
|
||||||
// If we have a local folder named 'shell' then use that rather than the one in node_modules
|
// 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.
|
// This will be the case in the main dashboard repository.
|
||||||
if (fs.existsSync(path.resolve(dir, 'shell'))) {
|
if (fs.existsSync(path.join(dir, 'shell'))) {
|
||||||
SHELL_ABS = path.resolve(dir, 'shell');
|
SHELL_ABS = path.join(dir, 'shell');
|
||||||
COMPONENTS_DIR = path.join(dir, 'pkg', 'rancher-components', 'src', 'components');
|
COMPONENTS_DIR = path.join(dir, 'pkg', 'rancher-components', 'src', 'components');
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===============================================================================================
|
return { SHELL_ABS, COMPONENTS_DIR };
|
||||||
// Functions for the UI Pluginas
|
};
|
||||||
// ===============================================================================================
|
|
||||||
|
|
||||||
const appConfig = _appConfig || {};
|
const getProxyConfig = (proxyConfig) => ({
|
||||||
const excludes = appConfig.excludes || [];
|
...proxyConfig,
|
||||||
|
'/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 watcherIgnores = [
|
/**
|
||||||
/node_modules/,
|
* @pkg imports must be resolved to the package that it importing them - this allows a package to use @pkg as an alias
|
||||||
/dist-pkg/,
|
* to the root of that particular package
|
||||||
/scripts\/standalone/
|
*/
|
||||||
|
const getPackageImport = (dir) => new webpack.NormalModuleReplacementPlugin(/^@pkg/, (resource) => {
|
||||||
|
const ctx = resource.context.split('/');
|
||||||
|
// Find 'pkg' folder in the context
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrument code for code coverage in e2e tests
|
||||||
|
*/
|
||||||
|
const instrumentCode = () => {
|
||||||
|
const instrumentedCode = (process.env.TEST_INSTRUMENT === 'true');
|
||||||
|
|
||||||
|
// Instrument code for tests
|
||||||
|
const babelPlugins = [
|
||||||
|
// TODO: Browser support; also add explanation to this TODO
|
||||||
|
// ['@babel/plugin-transform-modules-commonjs'],
|
||||||
|
['@babel/plugin-proposal-private-property-in-object', { loose: true }],
|
||||||
|
['@babel/plugin-proposal-class-properties', { loose: true }]
|
||||||
];
|
];
|
||||||
|
|
||||||
// Find any UI packages in node_modules
|
if (instrumentedCode) {
|
||||||
const NM = path.join(dir, 'node_modules');
|
babelPlugins.push([
|
||||||
const pkg = require(path.join(dir, 'package.json'));
|
'babel-plugin-istanbul', { extension: ['.js', '.vue'] }, 'add-vue'
|
||||||
const nmPackages = {};
|
]);
|
||||||
|
|
||||||
if (pkg && pkg.dependencies) {
|
console.warn('Instrumenting code for coverage'); // eslint-disable-line no-console
|
||||||
Object.keys(pkg.dependencies).forEach((pkg) => {
|
}
|
||||||
const f = require(path.join(NM, pkg, 'package.json'));
|
};
|
||||||
|
|
||||||
|
const getLoaders = (SHELL_ABS) => [
|
||||||
|
// 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'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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: 'frontmatter-markdown-loader',
|
||||||
|
options: { mode: ['body'] }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const getDevServerConfig = (proxy) => {
|
||||||
|
const harFile = process.env.HAR_FILE;
|
||||||
|
// HAR File support - load network responses from the specified .har file and use those rather than communicating to the Rancher server
|
||||||
|
const harData = harFile ? har.loadFile(harFile, devPorts ? 8005 : 80, '') : undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
client: { webSocketURL: { hostname: '0.0.0.0', port: devPorts ? 8005 : 80 } },
|
||||||
|
server: {
|
||||||
|
type: 'https',
|
||||||
|
options: {
|
||||||
|
key: fs.readFileSync(path.resolve(__dirname, 'server/server.key')),
|
||||||
|
cert: fs.readFileSync(path.resolve(__dirname, 'server/server.crt'))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
port: (devPorts ? 8005 : 80),
|
||||||
|
host: '0.0.0.0',
|
||||||
|
setupMiddlewares(middlewares, devServer) {
|
||||||
|
const socketProxies = {};
|
||||||
|
|
||||||
|
if (!devServer) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error('webpack-dev-server is not defined');
|
||||||
|
|
||||||
|
return middlewares;
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = devServer.app;
|
||||||
|
|
||||||
|
// Close down quickly in response to CTRL + C
|
||||||
|
process.once('SIGINT', () => {
|
||||||
|
devServer.close();
|
||||||
|
console.log('\n'); // eslint-disable-line no-console
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(serverMiddlewares);
|
||||||
|
|
||||||
|
if (harData) {
|
||||||
|
console.log('Installing HAR file middleware'); // eslint-disable-line no-console
|
||||||
|
app.use(har.harProxy(harData, process.env.HAR_DIR));
|
||||||
|
|
||||||
|
devServer.webSocketProxies.push({
|
||||||
|
upgrade(req, socket, head) {
|
||||||
|
const responseHeaders = ['HTTP/1.1 101 Web Socket Protocol Handshake', 'Upgrade: WebSocket', 'Connection: Upgrade'];
|
||||||
|
|
||||||
|
socket.write(`${ responseHeaders.join('\r\n') }\r\n\r\n`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(proxy).forEach((p) => {
|
||||||
|
const px = createProxyMiddleware({
|
||||||
|
...proxy[p],
|
||||||
|
ws: false // We will handle the web socket upgrade
|
||||||
|
});
|
||||||
|
|
||||||
|
if (proxy[p].ws) {
|
||||||
|
socketProxies[p] = px;
|
||||||
|
}
|
||||||
|
app.use(p, px);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Verify after migration completed
|
||||||
|
devServer.webSocketProxies.push({
|
||||||
|
upgrade(req, socket, head) {
|
||||||
|
const path = Object.keys(socketProxies).find((path) => req.url.startsWith(path));
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
const proxy = socketProxies[path];
|
||||||
|
|
||||||
|
if (proxy.upgrade) {
|
||||||
|
proxy.upgrade(req, socket, head);
|
||||||
|
} else {
|
||||||
|
console.log(`Upgrade for Proxy is not defined. Cannot upgrade Web socket for ${ req.url }`); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log(`Unknown Web socket upgrade request for ${ req.url }`); // eslint-disable-line no-console
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return middlewares;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a virtual module '@rancher/dynamic.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 getVirtualModules = (dir, includePkg) => {
|
||||||
|
// Find any UI packages in node_modules
|
||||||
|
const modulePaths = path.join(dir, 'node_modules');
|
||||||
|
const requiredPackages = require(path.join(dir, 'package.json'));
|
||||||
|
const librariesIndex = {};
|
||||||
|
|
||||||
|
if (requiredPackages && requiredPackages.dependencies) {
|
||||||
|
Object.keys(requiredPackages.dependencies).forEach((requiredPackage) => {
|
||||||
|
const library = require(path.join(modulePaths, requiredPackage, 'package.json'));
|
||||||
|
|
||||||
// The package.json must have the 'rancher' property to mark it as a UI package
|
// The package.json must have the 'rancher' property to mark it as a UI package
|
||||||
if (f.rancher) {
|
if (library.rancher) {
|
||||||
const id = `${ f.name }-${ f.version }`;
|
const id = `${ library.name }-${ library.version }`;
|
||||||
|
|
||||||
nmPackages[id] = f.main;
|
librariesIndex[id] = library.main;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function includePkg(name) {
|
let reqs = '';
|
||||||
|
const pkgFolder = path.relative(dir, './pkg');
|
||||||
|
|
||||||
|
if (fs.existsSync(pkgFolder)) {
|
||||||
|
fs.readdirSync(pkgFolder)
|
||||||
|
.filter((name) => !name.startsWith('.')) // Ignore hidden folders
|
||||||
|
.forEach((name) => {
|
||||||
|
const library = require(path.join(dir, 'pkg', name, 'package.json'));
|
||||||
|
|
||||||
|
// Package file must have rancher field to be a plugin
|
||||||
|
if (includePkg(name) && library.rancher) {
|
||||||
|
reqs += `$plugin.initPlugin('${ name }', require(\'~/pkg/${ name }\')); `;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(librariesIndex).forEach((i) => {
|
||||||
|
reqs += `$plugin.loadAsync('${ i }', '/pkg/${ i }/${ librariesIndex[i] }');`;
|
||||||
|
});
|
||||||
|
|
||||||
|
return new VirtualModulesPlugin({ 'node_modules/@rancher/dynamic.js': `export default function ($plugin) { ${ reqs } };` });
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAutoImport = () => new webpack.NormalModuleReplacementPlugin(/^@rancher\/auto-import$/, (resource) => {
|
||||||
|
const ctx = resource.context.split('/');
|
||||||
|
const pkg = ctx[ctx.length - 1];
|
||||||
|
|
||||||
|
resource.request = `@rancher/auto-import/${ pkg }`;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 getVirtualModulesAutoImport = (dir) => {
|
||||||
|
const autoImportTypes = {};
|
||||||
|
const pkgFolder = path.relative(dir, './pkg');
|
||||||
|
|
||||||
|
if (fs.existsSync(pkgFolder)) {
|
||||||
|
fs.readdirSync(pkgFolder)
|
||||||
|
.filter((name) => !name.startsWith('.')) // Ignore hidden folders
|
||||||
|
.forEach((name) => {
|
||||||
|
autoImportTypes[`node_modules/@rancher/auto-import/${ name }`] = generateDynamicTypeImport(`@pkg/${ name }`, path.join(dir, `pkg/${ name }`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new VirtualModulesPlugin(autoImportTypes);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
const createEnvVariablesPlugin = (routerBasePath, rancherEnv) => new webpack.DefinePlugin({
|
||||||
|
'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.loginLocaleSelector': JSON.stringify(process.env.LOGIN_LOCALE_SELECTOR || 'true'),
|
||||||
|
'process.env.excludeOperatorPkg': JSON.stringify(process.env.EXCLUDE_OPERATOR_PKG || 'false'),
|
||||||
|
'process.env.rancherEnv': JSON.stringify(rancherEnv),
|
||||||
|
'process.env.harvesterPkgUrl': JSON.stringify(process.env.HARVESTER_PKG_URL),
|
||||||
|
'process.env.api': JSON.stringify(api),
|
||||||
|
// Store the Router Base as env variable that we can use in `shell/config/router.js`
|
||||||
|
'process.env.routerBase': JSON.stringify(routerBasePath),
|
||||||
|
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false',
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure we process files in the @rancher/shell folder
|
||||||
|
*/
|
||||||
|
const processShellFiles = (config, SHELL_ABS) => {
|
||||||
|
config.module.rules.forEach((rule) => {
|
||||||
|
if ('test.js'.match(rule.test)) {
|
||||||
|
if (rule.exclude) {
|
||||||
|
const orig = rule.exclude;
|
||||||
|
|
||||||
|
rule.exclude = function(modulePath) {
|
||||||
|
if (modulePath.indexOf(SHELL_ABS) === 0 || typeof orig !== 'function') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return orig(modulePath);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update vue-loader to set whitespace to 'preserve'
|
||||||
|
* This was the setting with nuxt, but is not the default with vue cli
|
||||||
|
* Need to find the vue loader in the webpack config and update the setting
|
||||||
|
*/
|
||||||
|
const preserveWhitespace = (config) => {
|
||||||
|
config.module.rules.forEach((loader) => {
|
||||||
|
if (loader.use) {
|
||||||
|
loader.use.forEach((use) => {
|
||||||
|
if (use.loader.includes('vue-loader')) {
|
||||||
|
use.options.compilerOptions = { ...use.options.compilerOptions, whitespace: 'preserve' };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const printLogs = (dev, dashboardVersion, resourceBase, routerBasePath, pl, rancherEnv) => {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`API: '${ api }'. Env: '${ rancherEnv }'`); // eslint-disable-line no-console
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add ignored paths based on env var configuration and known cases
|
||||||
|
* TODO: Verify after migration completed
|
||||||
|
* In Webpack5 only RegExp, string and [string] types are accepted
|
||||||
|
* https://webpack.js.org/configuration/watch/#watchoptionsignored
|
||||||
|
* Example conversion:
|
||||||
|
* - as list: [/.shell/, /dist-pkg/, /scripts\/standalone/, /\/pkg.test-pkg/, /\/pkg.harvester/]
|
||||||
|
* - as chained regex rule: /.shell|dist-pkg|scripts\/standalone|\/pkg.test-pkg|\/pkg.harvester/
|
||||||
|
*/
|
||||||
|
const getWatcherIgnored = (excludes) => {
|
||||||
|
const paths = [
|
||||||
|
/node_modules/,
|
||||||
|
/dist-pkg/,
|
||||||
|
/scripts\/standalone/,
|
||||||
|
];
|
||||||
|
const pathExcludedPkg = excludes.map((excluded) => new RegExp(`/pkg.${ excluded }`));
|
||||||
|
const pathsCombined = [...paths, ...pathExcludedPkg];
|
||||||
|
const regexCombined = new RegExp(pathsCombined.map(({ source }) => source).join('|'));
|
||||||
|
|
||||||
|
return regexCombined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 the first argument so that we can derive folder locations
|
||||||
|
* from it, rather than from the location of this file
|
||||||
|
*/
|
||||||
|
module.exports = function(dir, _appConfig) {
|
||||||
|
require('events').EventEmitter.defaultMaxListeners = 20;
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
const { SHELL_ABS, COMPONENTS_DIR } = getShellPaths(dir);
|
||||||
|
const appConfig = _appConfig || {};
|
||||||
|
const excludes = appConfig.excludes || [];
|
||||||
|
|
||||||
|
const includePkg = (name) => {
|
||||||
if (name.startsWith('.') || name === 'node_modules') {
|
if (name.startsWith('.') || name === 'node_modules') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !excludes || (excludes && !excludes.includes(name));
|
return !excludes || (excludes && !excludes.includes(name));
|
||||||
}
|
};
|
||||||
|
|
||||||
// For each package in the pkg folder that is being compiled into the application,
|
const routerBasePath = process.env.ROUTER_BASE ?? '/';
|
||||||
// Add in the code to automatically import the types from that package
|
let resourceBase = process.env.RESOURCE_BASE ?? '';
|
||||||
// This imports models, edit, detail, list etc
|
const outputDir = process.env.OUTPUT_DIR ?? 'dist';
|
||||||
// When built as a UI package, shell/pkg/vue.config.js does the same thing
|
const rancherEnv = process.env.RANCHER_ENV || 'web';
|
||||||
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 }\')); `;
|
|
||||||
}
|
|
||||||
|
|
||||||
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) => {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// ===============================================================================================
|
|
||||||
// Dashboard nuxt configuration
|
|
||||||
// ===============================================================================================
|
|
||||||
|
|
||||||
require('events').EventEmitter.defaultMaxListeners = 50;
|
|
||||||
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('/') ) {
|
if ( resourceBase && !resourceBase.endsWith('/') ) {
|
||||||
resourceBase += '/';
|
resourceBase += '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Build: ${ dev ? 'Development' : 'Production' }`); // eslint-disable-line no-console
|
printLogs(dev, dashboardVersion, resourceBase, routerBasePath, pl, rancherEnv);
|
||||||
|
|
||||||
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';
|
|
||||||
|
|
||||||
const loginLocaleSelector = process.env.LOGIN_LOCALE_SELECTOR || 'true';
|
|
||||||
const excludeOperatorPkg = process.env.EXCLUDE_OPERATOR_PKG || 'false';
|
|
||||||
|
|
||||||
console.log(`API: '${ api }'. Env: '${ rancherEnv }'`); // eslint-disable-line no-console
|
|
||||||
const proxy = {
|
|
||||||
...appConfig.proxies,
|
|
||||||
'/k8s': configHelper.proxyWsOpts(api), // Straight to a remote cluster (/k8s/clusters/<id>/)
|
|
||||||
'/pp': configHelper.proxyWsOpts(api), // For (epinio) standalone API
|
|
||||||
'/api': configHelper.proxyWsOpts(api), // Management k8s API
|
|
||||||
'/apis': configHelper.proxyWsOpts(api), // Management k8s API
|
|
||||||
'/v1': configHelper.proxyWsOpts(api), // Management Steve API
|
|
||||||
'/v3': configHelper.proxyWsOpts(api), // Rancher API
|
|
||||||
'/v3-public': configHelper.proxyOpts(api), // Rancher Unauthed API
|
|
||||||
'/api-ui': configHelper.proxyOpts(api), // Browser API UI
|
|
||||||
'/meta': configHelper.proxyMetaOpts(api), // Browser API UI
|
|
||||||
'/v1-*': configHelper.proxyOpts(api), // SAML, KDM, etc
|
|
||||||
'/rancherversion': configHelper.proxyPrimeOpts(api), // Rancher version endpoint
|
|
||||||
// These are for Ember embedding
|
|
||||||
'/c/*/edit': configHelper.proxyOpts('https://127.0.0.1:8000'), // Can't proxy all of /c because that's used by Vue too
|
|
||||||
'/k/': configHelper.proxyOpts('https://127.0.0.1:8000'),
|
|
||||||
'/g/': configHelper.proxyOpts('https://127.0.0.1:8000'),
|
|
||||||
'/n/': configHelper.proxyOpts('https://127.0.0.1:8000'),
|
|
||||||
'/p/': configHelper.proxyOpts('https://127.0.0.1:8000'),
|
|
||||||
'/assets': configHelper.proxyOpts('https://127.0.0.1:8000'),
|
|
||||||
'/translations': configHelper.proxyOpts('https://127.0.0.1:8000'),
|
|
||||||
'/engines-dist': configHelper.proxyOpts('https://127.0.0.1:8000'),
|
|
||||||
};
|
|
||||||
|
|
||||||
// HAR File support - load network responses from the specified .har file and use those rather than communicating to the Rancher server
|
|
||||||
const harFile = process.env.HAR_FILE;
|
|
||||||
let harData;
|
|
||||||
|
|
||||||
if (harFile) {
|
|
||||||
harData = har.loadFile(harFile, devPorts ? 8005 : 80, ''); // eslint-disable-line no-console
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const proxy = getProxyConfig(appConfig.proxy);
|
||||||
const config = {
|
const config = {
|
||||||
// Vue server
|
// Vue server
|
||||||
devServer: {
|
devServer: getDevServerConfig(proxy),
|
||||||
client: { webSocketURL: { hostname: '0.0.0.0', port: devPorts ? 8005 : 80 } },
|
publicPath: resourceBase || undefined,
|
||||||
server: {
|
css: {
|
||||||
type: 'https',
|
|
||||||
options: {
|
|
||||||
key: fs.readFileSync(path.resolve(__dirname, 'server/server.key')),
|
|
||||||
cert: fs.readFileSync(path.resolve(__dirname, 'server/server.crt'))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
port: (devPorts ? 8005 : 80),
|
|
||||||
host: '0.0.0.0',
|
|
||||||
setupMiddlewares(middlewares, devServer) {
|
|
||||||
const socketProxies = {};
|
|
||||||
|
|
||||||
if (!devServer) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error('webpack-dev-server is not defined');
|
|
||||||
|
|
||||||
return middlewares;
|
|
||||||
}
|
|
||||||
|
|
||||||
const app = devServer.app;
|
|
||||||
|
|
||||||
// Close down quickly in response to CTRL + C
|
|
||||||
process.once('SIGINT', () => {
|
|
||||||
devServer.close();
|
|
||||||
console.log('\n'); // eslint-disable-line no-console
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(serverMiddlewares);
|
|
||||||
|
|
||||||
if (harData) {
|
|
||||||
console.log('Installing HAR file middleware'); // eslint-disable-line no-console
|
|
||||||
app.use(har.harProxy(harData, process.env.HAR_DIR));
|
|
||||||
|
|
||||||
devServer.webSocketProxies.push({
|
|
||||||
upgrade(req, socket, head) {
|
|
||||||
const responseHeaders = ['HTTP/1.1 101 Web Socket Protocol Handshake', 'Upgrade: WebSocket', 'Connection: Upgrade'];
|
|
||||||
|
|
||||||
socket.write(`${ responseHeaders.join('\r\n') }\r\n\r\n`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.keys(proxy).forEach((p) => {
|
|
||||||
const px = createProxyMiddleware({
|
|
||||||
...proxy[p],
|
|
||||||
ws: false // We will handle the web socket upgrade
|
|
||||||
});
|
|
||||||
|
|
||||||
if (proxy[p].ws) {
|
|
||||||
socketProxies[p] = px;
|
|
||||||
}
|
|
||||||
app.use(p, px);
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: Verify after migration completed
|
|
||||||
devServer.webSocketProxies.push({
|
|
||||||
upgrade(req, socket, head) {
|
|
||||||
const path = Object.keys(socketProxies).find((path) => req.url.startsWith(path));
|
|
||||||
|
|
||||||
if (path) {
|
|
||||||
const proxy = socketProxies[path];
|
|
||||||
|
|
||||||
if (proxy.upgrade) {
|
|
||||||
proxy.upgrade(req, socket, head);
|
|
||||||
} else {
|
|
||||||
console.log(`Upgrade for Proxy is not defined. Cannot upgrade Web socket for ${ req.url }`); // eslint-disable-line no-console
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log(`Unknown Web socket upgrade request for ${ req.url }`); // eslint-disable-line no-console
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return middlewares;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
transpileDependencies: true,
|
|
||||||
publicPath: resourceBase || undefined,
|
|
||||||
css: {
|
|
||||||
extract: false, // inline css styles instead of including with `<links`
|
extract: false, // inline css styles instead of including with `<links`
|
||||||
loaderOptions: {
|
loaderOptions: {
|
||||||
sass: {
|
sass: {
|
||||||
|
|
@ -340,16 +515,13 @@ module.exports = function(dir, _appConfig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
outputDir,
|
outputDir,
|
||||||
|
|
||||||
pages: {
|
pages: {
|
||||||
index: {
|
index: {
|
||||||
entry: path.join(SHELL_ABS, '/initialize/entry.js'),
|
entry: path.join(SHELL_ABS, '/initialize/entry.js'),
|
||||||
template: path.join(SHELL_ABS, '/public/index.html')
|
template: path.join(SHELL_ABS, '/public/index.html')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
configureWebpack(config) {
|
configureWebpack(config) {
|
||||||
// TODO VUE3: We may want to look into what we want the value to actually be. For the time being this was causing a warning in our CLI because it would set process.env.NODE_ENV to 'development' even thought it was
|
// TODO VUE3: We may want to look into what we want the value to actually be. For the time being this was causing a warning in our CLI because it would set process.env.NODE_ENV to 'development' even thought it was
|
||||||
// already set to 'dev' and we're using 'dev' in other locations so I don't think we want to do that. Config details found here: https://webpack.js.org/configuration/optimization/#optimizationnodeenv.
|
// already set to 'dev' and we're using 'dev' in other locations so I don't think we want to do that. Config details found here: https://webpack.js.org/configuration/optimization/#optimizationnodeenv.
|
||||||
|
|
@ -364,57 +536,21 @@ module.exports = function(dir, _appConfig) {
|
||||||
config.resolve.alias['@components'] = COMPONENTS_DIR;
|
config.resolve.alias['@components'] = COMPONENTS_DIR;
|
||||||
config.resolve.alias['vue$'] = dev ? path.resolve(process.cwd(), 'node_modules', 'vue') : 'vue';
|
config.resolve.alias['vue$'] = dev ? path.resolve(process.cwd(), 'node_modules', 'vue') : 'vue';
|
||||||
config.resolve.modules.push(__dirname);
|
config.resolve.modules.push(__dirname);
|
||||||
config.plugins.push(virtualModules);
|
config.plugins.push(getVirtualModules(dir, includePkg));
|
||||||
config.plugins.push(autoImport);
|
config.plugins.push(getAutoImport());
|
||||||
config.plugins.push(new VirtualModulesPlugin(autoImportTypes));
|
config.plugins.push(getVirtualModulesAutoImport(dir));
|
||||||
config.plugins.push(pkgImport);
|
config.plugins.push(getPackageImport(dir));
|
||||||
|
config.plugins.push(createEnvVariablesPlugin(routerBasePath, rancherEnv));
|
||||||
config.plugins.push(new NodePolyfillPlugin()); // required from Webpack 5 to polyfill node modules
|
config.plugins.push(new NodePolyfillPlugin()); // required from Webpack 5 to polyfill node modules
|
||||||
// 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.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.loginLocaleSelector': JSON.stringify(loginLocaleSelector),
|
|
||||||
'process.env.excludeOperatorPkg': JSON.stringify(excludeOperatorPkg),
|
|
||||||
'process.env.rancherEnv': JSON.stringify(rancherEnv),
|
|
||||||
'process.env.harvesterPkgUrl': JSON.stringify(process.env.HARVESTER_PKG_URL),
|
|
||||||
'process.env.api': JSON.stringify(api),
|
|
||||||
// Store the Router Base as env variable that we can use in `shell/config/router.js`
|
|
||||||
'process.env.routerBase': JSON.stringify(routerBasePath),
|
|
||||||
|
|
||||||
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false',
|
|
||||||
|
|
||||||
// This is a replacement of the nuxt publicRuntimeConfig
|
|
||||||
'nuxt.publicRuntimeConfig': JSON.stringify({
|
|
||||||
rancherEnv,
|
|
||||||
dashboardVersion
|
|
||||||
}),
|
|
||||||
|
|
||||||
}));
|
|
||||||
|
|
||||||
// The static assets need to be in the built assets directory in order to get served (primarily the favicon)
|
// The static assets need to be in the built assets directory in order to get served (primarily the favicon)
|
||||||
config.plugins.push(new CopyWebpackPlugin({ patterns: [{ from: path.join(SHELL_ABS, 'static'), to: '.' }] }));
|
config.plugins.push(new CopyWebpackPlugin({ patterns: [{ from: path.join(SHELL_ABS, 'static'), to: '.' }] }));
|
||||||
|
|
||||||
config.resolve.extensions.push(...['.tsx', '.ts', '.js', '.vue', '.scss']);
|
config.resolve.extensions.push(...['.tsx', '.ts', '.js', '.vue', '.scss']);
|
||||||
|
config.watchOptions = {
|
||||||
/**
|
...(config.watchOptions || {}),
|
||||||
* Add ignored paths based on env var configuration and known cases
|
ignored: getWatcherIgnored(excludes)
|
||||||
* TODO: Verify after migration completed
|
};
|
||||||
* In Webpack5 only RegExp, string and [string] types are accepted
|
|
||||||
* https://webpack.js.org/configuration/watch/#watchoptionsignored
|
|
||||||
* Example conversion:
|
|
||||||
* - as list: [/.shell/, /dist-pkg/, /scripts\/standalone/, /\/pkg.test-pkg/, /\/pkg.harvester/]
|
|
||||||
* - as chained regex rule: /.shell|dist-pkg|scripts\/standalone|\/pkg.test-pkg|\/pkg.harvester/
|
|
||||||
*/
|
|
||||||
config.watchOptions = config.watchOptions || {};
|
|
||||||
const ignoredPkgs = excludes.map((excluded) => new RegExp(`/pkg.${ excluded }`));
|
|
||||||
const watcherIgnoresPaths = [...watcherIgnores, ...ignoredPkgs];
|
|
||||||
const combinedRegex = new RegExp(watcherIgnoresPaths.map(({ source }) => source).join('|'));
|
|
||||||
|
|
||||||
config.watchOptions.ignored = combinedRegex;
|
|
||||||
|
|
||||||
if (dev) {
|
if (dev) {
|
||||||
config.devtool = 'cheap-module-source-map';
|
config.devtool = 'cheap-module-source-map';
|
||||||
|
|
@ -423,128 +559,10 @@ module.exports = function(dir, _appConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
config.resolve.symlinks = false;
|
config.resolve.symlinks = false;
|
||||||
|
processShellFiles(config, SHELL_ABS);
|
||||||
// Ensure we process files in the @rancher/shell folder
|
instrumentCode();
|
||||||
config.module.rules.forEach((r) => {
|
config.module.rules.push(...getLoaders(SHELL_ABS));
|
||||||
if ('test.js'.match(r.test)) {
|
preserveWhitespace(config);
|
||||||
if (r.exclude) {
|
|
||||||
const orig = r.exclude;
|
|
||||||
|
|
||||||
r.exclude = function(modulePath) {
|
|
||||||
if (modulePath.indexOf(SHELL_ABS) === 0 || typeof orig !== 'function') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return orig(modulePath);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Instrument code for tests
|
|
||||||
const babelPlugins = [
|
|
||||||
// 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', { extension: ['.js', '.vue'] }, 'add-vue'
|
|
||||||
]);
|
|
||||||
|
|
||||||
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'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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: 'frontmatter-markdown-loader',
|
|
||||||
options: { mode: ['body'] }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
config.module.rules.push(...loaders);
|
|
||||||
|
|
||||||
// TODO: Verify after migration completed
|
|
||||||
// Update vue-loader to set whitespace to 'preserve'
|
|
||||||
// This was the setting with nuxt, but is not the default with vue cli
|
|
||||||
// Need to find the vue loader in the webpack config and update the setting
|
|
||||||
config.module.rules.forEach((loader) => {
|
|
||||||
if (loader.use) {
|
|
||||||
loader.use.forEach((use) => {
|
|
||||||
if (use.loader.includes('vue-loader')) {
|
|
||||||
use.options.compilerOptions = { ...use.options.compilerOptions, whitespace: 'preserve' };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue