diff --git a/shell/creators/app/app.package.json b/shell/creators/app/app.package.json index c7993757e30..3cd6b5b9b0b 100644 --- a/shell/creators/app/app.package.json +++ b/shell/creators/app/app.package.json @@ -6,6 +6,10 @@ "node": ">=12" }, "dependencies": {}, + "devDependencies": { + "ts-loader": "6.2.2", + "@vue/cli-plugin-babel": "4.5.15" + }, "resolutions": { "**/webpack": "4", "@types/node": "^16" diff --git a/shell/creators/app/files/babel.config.js b/shell/creators/app/files/babel.config.js index ac41fa8d564..dcd9db785b2 100644 --- a/shell/creators/app/files/babel.config.js +++ b/shell/creators/app/files/babel.config.js @@ -1 +1,18 @@ -module.exports = require('@rancher/shell/babel.config.js'); +module.exports = { + env: { + test: { + plugins: [ + [ + 'module-resolver', + { + root: ['.'], + alias: { + '@': '.', + '~': '.', + }, + }, + ], + ], + }, + }, +}; diff --git a/shell/creators/app/files/vue.config.js b/shell/creators/app/files/vue.config.js index 5b55ecf2164..105b038f497 100644 --- a/shell/creators/app/files/vue.config.js +++ b/shell/creators/app/files/vue.config.js @@ -1,10 +1,7 @@ -/** - * 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 -}); +const config = require('./node_modules/@rancher/shell/vue.config'); -module.exports = require('./vue.config.ts').default; +module.exports = config(__dirname, { + excludes: [], + // excludes: ['fleet', 'example'] + // autoLoad: ['fleet', 'example'] +}); diff --git a/shell/creators/app/files/vue.config.ts b/shell/creators/app/files/vue.config.ts deleted file mode 100644 index 52938bdc239..00000000000 --- a/shell/creators/app/files/vue.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import config from '@rancher/shell/vue.config'; - -export default config(__dirname, { - excludes: [], - // excludes: ['fleet', 'example'] - // autoLoad: ['fleet', 'example'] -}); diff --git a/shell/creators/app/init b/shell/creators/app/init index c52b3d98a82..0806d287a2d 100755 --- a/shell/creators/app/init +++ b/shell/creators/app/init @@ -12,7 +12,6 @@ const targets = { const files = [ 'tsconfig.json', 'vue.config.js', - 'vue.config.ts', '.eslintignore', '.eslintrc.js', 'babel.config.js', diff --git a/shell/creators/pkg/init b/shell/creators/pkg/init index 26ed91e19ac..ee270c0cb0e 100755 --- a/shell/creators/pkg/init +++ b/shell/creators/pkg/init @@ -3,7 +3,7 @@ const fs = require('fs-extra'); const path = require('path'); -const targets = { +const targets = { // TODO: RC !!! These need to be converted to use vue cli dev: './node_modules/.bin/nuxt dev', nuxt: './node_modules/.bin/nuxt', }; @@ -16,8 +16,8 @@ const files = [ ]; const topLevelScripts = { - 'build-pkg': './node_modules/@rancher/shell/scripts/build-pkg.sh', - 'serve-pkgs': './node_modules/@rancher/shell/scripts/serve-pkgs', + 'build-pkg': './node_modules/@rancher/shell/scripts/build-pkg.sh', + 'serve-pkgs': './node_modules/@rancher/shell/scripts/serve-pkgs', 'publish-pkgs': './node_modules/@rancher/shell/scripts/extension/publish', }; diff --git a/shell/scripts/test-plugins-build.sh b/shell/scripts/test-plugins-build.sh index 461e6070883..d5f9b540ddc 100755 --- a/shell/scripts/test-plugins-build.sh +++ b/shell/scripts/test-plugins-build.sh @@ -108,13 +108,18 @@ if [ "${SKIP_STANDALONE}" == "false" ]; then yarn install echo "Building skeleton app" + # Fails. Fixed by adding "ts-loader": "^8.0.17" as devDependencies to shell/creators/app/app.package.json + # (note - @nuxt/typescript-build@2.1.0 brings in ts-loader@8.4.0, @vue/cli-plugin-typescript@4.5.15 brings in @vue/cli-plugin-typescript@4.5.15) FORCE_COLOR=true yarn build | cat # Package creator echo "Verifying package creator package" - yarn create @rancher/pkg test-pkg + yarn create @rancher/pkg test-pkg # succeeds echo "Building test package" + # Failures + # # 1 - Missing `@vue/cli-plugin-typescript` dep. Adding "@vue/cli-plugin-babel": "4.5.15" to app.package.json devDependencies causes `yarn build` from above to fail with `orig not function`` + # # 2 - Fix for `orign not function` `shell/vue.config.js` in `config.module.rules.forEach((r)` const orig = r.exclude.length ? r.exclude[0] : r.exclude. (r.exclude is now an array). Causes issues with worker files `Cannot read properties of undefined (reading 'options')`` FORCE_COLOR=true yarn build-pkg test-pkg | cat # Add test list component to the test package diff --git a/shell/vue.config.ts b/shell/vue.config.js similarity index 91% rename from shell/vue.config.ts rename to shell/vue.config.js index 8b97f0bb385..4909536800d 100644 --- a/shell/vue.config.ts +++ b/shell/vue.config.js @@ -1,11 +1,12 @@ -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 fs = require('fs'); +const path = require('path'); +const serveStatic = require('serve-static'); +const webpack = require('webpack'); +// const STANDARD = require('./config/private-label').STANDARD; +const STANDARD = 1; +const generateDynamicTypeImport = require('./pkg/auto-import').generateDynamicTypeImport; +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const createProxyMiddleware = require('http-proxy-middleware').createProxyMiddleware; const dev = (process.env.NODE_ENV !== 'production'); const devPorts = dev || process.env.DEV_PORTS === 'true'; @@ -32,7 +33,7 @@ if ( !api.startsWith('http') ) { // 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) { +module.exports = 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'); @@ -57,7 +58,7 @@ export default function(dir: any, _appConfig: any) { COMPONENTS_DIR = path.join(dir, 'pkg', 'rancher-components', 'src', 'components'); } - const babelPlugins: string | (string | object)[] = [ + const babelPlugins = [ // TODO: Browser support // ['@babel/plugin-transform-modules-commonjs'], ['@babel/plugin-proposal-private-property-in-object', { loose: true }] @@ -85,7 +86,7 @@ export default function(dir: any, _appConfig: any) { /scripts\/standalone/ ]; - autoLoad.forEach((pkg: any) => { + 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 }`; @@ -104,7 +105,7 @@ export default function(dir: any, _appConfig: any) { // 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 = {}; + const nmPackages = {}; if (pkg && pkg.dependencies) { Object.keys(pkg.dependencies).forEach((pkg) => { @@ -127,7 +128,7 @@ export default function(dir: any, _appConfig: any) { serverMiddleware.push({ path: '/uiplugins-catalog', - handler: (req: any, res: any, next: any) => { + handler: (req, res, next) => { const p = req.url.split('?'); try { @@ -143,7 +144,7 @@ export default function(dir: any, _appConfig: any) { } }); - function includePkg(name: any) { + function includePkg(name) { if (name.startsWith('.') || name === 'node_modules') { return false; } @@ -151,7 +152,7 @@ export default function(dir: any, _appConfig: any) { return !excludes || (excludes && !excludes.includes(name)); } - excludes.forEach((e: any) => { + excludes.forEach((e) => { watcherIgnores.push(new RegExp(`/pkg.${ e }`)); }); @@ -159,7 +160,7 @@ export default function(dir: any, _appConfig: any) { // 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 autoImportTypes = {}; const VirtualModulesPlugin = require('webpack-virtual-modules'); let reqs = ''; const pkgFolder = path.relative(dir, './pkg'); @@ -194,7 +195,7 @@ export default function(dir: any, _appConfig: any) { // 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 autoImport = new webpack.NormalModuleReplacementPlugin(/^@rancher\/auto-import$/, (resource) => { const ctx = resource.context.split('/'); const pkg = ctx[ctx.length - 1]; @@ -203,10 +204,10 @@ export default function(dir: any, _appConfig: any) { // @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 pkgImport = new webpack.NormalModuleReplacementPlugin(/^@pkg/, (resource) => { const ctx = resource.context.split('/'); // Find 'pkg' folder in the contxt - const index = ctx.findIndex((s: any) => s === 'pkg'); + const index = ctx.findIndex(s => s === 'pkg'); if (index !== -1 && (index + 1) < ctx.length) { const pkg = ctx[index + 1]; @@ -312,8 +313,8 @@ export default function(dir: any, _appConfig: any) { 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 = {}; + before(app, server) { + const socketProxies = {}; Object.keys(proxy).forEach((p) => { const px = createProxyMiddleware({ @@ -321,18 +322,24 @@ export default function(dir: any, _appConfig: any) { ws: false // We will handle the web socket upgrade }); - proxies[p] = px; + if (proxy[p].ws) { + socketProxies[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); + 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 } @@ -364,7 +371,7 @@ export default function(dir: any, _appConfig: any) { } }, - configureWebpack(config: any) { + configureWebpack(config) { config.resolve.alias['~'] = dir; config.resolve.alias['@'] = dir; config.resolve.alias['~assets'] = path.join(__dirname, 'assets'); @@ -418,12 +425,12 @@ export default function(dir: any, _appConfig: any) { config.resolve.symlinks = false; // Ensure we process files in the @rancher/shell folder - config.module.rules.forEach((r: any) => { + config.module.rules.forEach((r) => { if ('test.js'.match(r.test)) { if (r.exclude) { - const orig = r.exclude; + const orig = r.exclude.length ? r.exclude[0] : r.exclude; - r.exclude = function(modulePath: string) { + r.exclude = function(modulePath) { if (modulePath.indexOf(SHELL_ABS) === 0) { return false; } @@ -435,7 +442,7 @@ export default function(dir: any, _appConfig: any) { }); // Instrument code for tests - const babelPlugins: (string | ([] | Object)[])[] = [ + const babelPlugins = [ // TODO: Browser support // ['@babel/plugin-transform-modules-commonjs'], ['@babel/plugin-proposal-private-property-in-object', { loose: true }], @@ -557,13 +564,13 @@ export default function(dir: any, _appConfig: any) { }; return config; -} +}; // =============================================================================================== // Functions for the request proxying used in dev // =============================================================================================== -function proxyMetaOpts(target: any) { +function proxyMetaOpts(target) { return { target, followRedirects: true, @@ -575,7 +582,7 @@ function proxyMetaOpts(target: any) { }; } -function proxyOpts(target: any) { +function proxyOpts(target) { return { target, secure: !devPorts, @@ -588,7 +595,7 @@ function proxyOpts(target: any) { // Intercept the /rancherversion API call wnad modify the 'RancherPrime' value // if configured to do so by the environment variable PRIME -function proxyPrimeOpts(target: any) { +function proxyPrimeOpts(target) { const opts = proxyOpts(target); // Don't intercept if the PRIME environment variable is not set @@ -600,7 +607,7 @@ function proxyPrimeOpts(target: any) { const _end = res.end; let body = ''; - proxyRes.on( 'data', (data: any) => { + proxyRes.on( 'data', (data) => { data = data.toString('utf-8'); body += data; }); @@ -629,13 +636,13 @@ function proxyPrimeOpts(target: any) { return opts; } -function onProxyRes(proxyRes: any, req: any, res: any) { +function onProxyRes(proxyRes, req, res) { if (devPorts) { proxyRes.headers['X-Frame-Options'] = 'ALLOWALL'; } } -function proxyWsOpts(target: any) { +function proxyWsOpts(target) { return { ...proxyOpts(target), ws: true, @@ -643,26 +650,26 @@ function proxyWsOpts(target: any) { }; } -function onProxyReq(proxyReq: any, req: any) { +function onProxyReq(proxyReq, req) { 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) { +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: any) => { + socket.on('error', (err) => { console.error('Proxy WS Error:', err); // eslint-disable-line no-console }); } -function onError(err: any, req: any, res: any) { +function onError(err, req, res) { res.statusCode = 598; console.error('Proxy Error:', err); // eslint-disable-line no-console res.write(JSON.stringify(err)); diff --git a/vue.config.js b/vue.config.js index fbdca9fd47e..229f7f26bad 100644 --- a/vue.config.js +++ b/vue.config.js @@ -1,7 +1,16 @@ -require('ts-node').register({ - project: './tsconfig.json', - compilerOptions: { module: 'commonjs' }, - logError: true -}); -module.exports = require('./vue.config.ts').default; +const config = require('./shell/vue.config'); + +// Excludes the following plugins if there's no .env file. +let defaultExcludes = 'epinio, rancher-components, harvester'; + +if (process.env.RANCHER_ENV === 'harvester') { + defaultExcludes = defaultExcludes.replace(', harvester', ''); +} +const excludes = process.env.EXCLUDES_PKG || defaultExcludes; + +module.exports = config(__dirname, { + excludes: excludes.replace(/\s/g, '').split(','), + // excludes: ['fleet', 'example'] + // autoLoad: ['fleet', 'example'] +}); diff --git a/vue.config.ts b/vue.config.ts deleted file mode 100644 index 2238ac618ea..00000000000 --- a/vue.config.ts +++ /dev/null @@ -1,16 +0,0 @@ - -import config from './shell/vue.config'; - -// Excludes the following plugins if there's no .env file. -let defaultExcludes = 'epinio, rancher-components, harvester'; - -if (process.env.RANCHER_ENV === 'harvester') { - defaultExcludes = defaultExcludes.replace(', harvester', ''); -} -const excludes = process.env.EXCLUDES_PKG || defaultExcludes; - -export default config(__dirname, { - excludes: excludes.replace(/\s/g, '').split(','), - // excludes: ['fleet', 'example'] - // autoLoad: ['fleet', 'example'] -});