Skip to content

Commit

Permalink
update frontend to support module federation
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Vogt <[email protected]>
  • Loading branch information
christianvogt committed Feb 12, 2025
1 parent 48e7884 commit 1e24707
Show file tree
Hide file tree
Showing 13 changed files with 1,122 additions and 183 deletions.
14 changes: 8 additions & 6 deletions clients/ui/bff/internal/api/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@ import (
const (
Version = "1.0.0"

PathPrefix = "/api/v1"
PathPrefix = "/model-registry"
ApiPathPrefix = "/api/v1"
ModelRegistryId = "model_registry_id"
RegisteredModelId = "registered_model_id"
ModelVersionId = "model_version_id"
ModelArtifactId = "model_artifact_id"
ArtifactId = "artifact_id"
HealthCheckPath = PathPrefix + "/healthcheck"
UserPath = PathPrefix + "/user"
ModelRegistryListPath = PathPrefix + "/model_registry"
NamespaceListPath = PathPrefix + "/namespaces"
HealthCheckPath = ApiPathPrefix + "/healthcheck"
UserPath = ApiPathPrefix + "/user"
ModelRegistryListPath = ApiPathPrefix + "/model_registry"
NamespaceListPath = ApiPathPrefix + "/namespaces"
ModelRegistryPath = ModelRegistryListPath + "/:" + ModelRegistryId
RegisteredModelListPath = ModelRegistryPath + "/registered_models"
RegisteredModelPath = RegisteredModelListPath + "/:" + RegisteredModelId
Expand Down Expand Up @@ -130,7 +131,8 @@ func (app *App) Routes() http.Handler {
appMux := http.NewServeMux()

// handler for api calls
appMux.Handle("/api/v1/", apiRouter)
appMux.Handle(ApiPathPrefix+"/", apiRouter)
appMux.Handle(PathPrefix+ApiPathPrefix+"/", http.StripPrefix(PathPrefix, apiRouter))

// file server for the frontend file and SPA routes
staticDir := http.Dir(app.config.StaticAssetsDir)
Expand Down
11 changes: 6 additions & 5 deletions clients/ui/bff/internal/api/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ import (
"context"
"errors"
"fmt"
"log/slog"
"net/http"
"runtime/debug"
"strings"

"github.com/google/uuid"
"github.com/julienschmidt/httprouter"
"github.com/kubeflow/model-registry/ui/bff/internal/config"
"github.com/kubeflow/model-registry/ui/bff/internal/constants"
"github.com/kubeflow/model-registry/ui/bff/internal/integrations"
"github.com/rs/cors"
"log/slog"
"net/http"
"runtime/debug"
"strings"
)

func (app *App) RecoverPanic(next http.Handler) http.Handler {
Expand All @@ -34,7 +35,7 @@ func (app *App) InjectUserHeaders(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

//skip use headers check if we are not on /api/v1
if !strings.HasPrefix(r.URL.Path, PathPrefix) {
if !strings.HasPrefix(r.URL.Path, ApiPathPrefix) && !strings.HasPrefix(r.URL.Path, PathPrefix+ApiPathPrefix) {
next.ServeHTTP(w, r)
return
}
Expand Down
23 changes: 1 addition & 22 deletions clients/ui/docs/kubeflow-development-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,7 @@

```javascript
proxy: {
'/api/v1': {
target: 'http://localhost:4000',
},
'/api': {
target: 'http://localhost:8082',
},
'/jupyter': {
target: 'http://localhost:8085',
pathRewrite: {'^/jupyter': ''},
},
// NOTE: this makes `/notebook` requests fail with a 504 error
'/notebook': {
target: 'http://localhost:8086',
pathRewrite: {
'^/notebook/(.*?)/(.*?)/(.*)':
'/$1/services/$2/proxy/notebook/$1/$2/$3',
},
},
'/pipeline': {
target: 'http://localhost:8087',
pathRewrite: {'^/pipeline': ''},
},
...
'/model-registry': {
target: 'http://localhost:9000',
changeOrigin: true,
Expand Down
4 changes: 2 additions & 2 deletions clients/ui/frontend/config/dotenv.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,14 @@ const setupDotenvFilesForEnv = ({ env }) => {
const SRC_DIR = path.resolve(RELATIVE_DIRNAME, process.env.SRC_DIR || TS_BASE_URL || 'src');
const COMMON_DIR = path.resolve(RELATIVE_DIRNAME, process.env.COMMON_DIR || '../common');
const DIST_DIR = path.resolve(RELATIVE_DIRNAME, process.env.DIST_DIR || TS_OUT_DIR || 'public');
const DEPLOYMENT_MODE = process.env.DEPLOYMENT_MODE || 'integrated';
const HOST = process.env.HOST || DEPLOYMENT_MODE === 'integrated' ? '0.0.0.0' : 'localhost';
const HOST = process.env.HOST || 'localhost';
const PORT = process.env.PORT || '9000';
const PROXY_PROTOCOL = process.env.PROXY_PROTOCOL || 'http';
const PROXY_HOST = process.env.PROXY_HOST || 'localhost';
const PROXY_PORT = process.env.PROXY_PORT || process.env.PORT || 4000;
const DEV_MODE = process.env.DEV_MODE || undefined;
const OUTPUT_ONLY = process.env._OUTPUT_ONLY === 'true';
const DEPLOYMENT_MODE = process.env.DEPLOYMENT_MODE || 'integrated';

process.env._RELATIVE_DIRNAME = RELATIVE_DIRNAME;
process.env._IS_PROJECT_ROOT_DIR = IS_ROOT;
Expand Down
38 changes: 38 additions & 0 deletions clients/ui/frontend/config/moduleFederation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const path = require('path');
const ModuleFederationPlugin = require('webpack').container.ModuleFederationPlugin;

const {
NativeFederationTypeScriptRemote,
} = require('@module-federation/native-federation-typescript/webpack');

const deps = require('../package.json').dependencies;

const moduleFederationConfig = {
name: 'modelRegistry',
filename: 'remoteEntry.js',
shared: {
react: { singleton: true, eager: true, requiredVersion: deps.react },
'react-dom': { singleton: true, eager: true, requiredVersion: deps['react-dom'] },
'react-router': { singleton: true, eager: true, requiredVersion: deps['react-router'] },
'react-router-dom': { singleton: true, eager: true, requiredVersion: deps['react-router-dom'] },
},
exposes: {
// TODO expose modules. eg:
// './index': './src/plugin/index.tsx',
// './plugin': './src/plugin/index.tsx',
},
// For module federation to work when optimization.runtimeChunk="single":
// See https://github.com/webpack/webpack/issues/18810
runtime: false,
};

module.exports = {
moduleFederationPlugins: [
new ModuleFederationPlugin(moduleFederationConfig),
// TODO enable once modules are exposed
// NativeFederationTypeScriptRemote({
// moduleFederationConfig,
// tsConfigPath: path.resolve(__dirname, '../tsconfig.json'),
// }),
],
};
14 changes: 10 additions & 4 deletions clients/ui/frontend/config/webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const { setupWebpackDotenvFilesForEnv } = require('./dotenv');

const { moduleFederationPlugins } = require('./moduleFederation');

const RELATIVE_DIRNAME = process.env._RELATIVE_DIRNAME;
const IS_PROJECT_ROOT_DIR = process.env._IS_PROJECT_ROOT_DIR;
const IMAGES_DIRNAME = process.env._IMAGES_DIRNAME;
Expand All @@ -19,7 +21,7 @@ const BASE_PATH = DEPLOYMENT_MODE === 'integrated' ? '/model-registry/' : PUBLIC

if (OUTPUT_ONLY !== 'true') {
console.info(
`\nPrepping files...\n SRC DIR: ${SRC_DIR}\n OUTPUT DIR: ${DIST_DIR}\n PUBLIC PATH: ${PUBLIC_PATH}\n`,
`\nPrepping files...\n SRC DIR: ${SRC_DIR}\n OUTPUT DIR: ${DIST_DIR}\n PUBLIC PATH: ${PUBLIC_PATH}\n BASE_PATH: ${BASE_PATH}\n`,
);
if (COVERAGE === 'true') {
console.info('\nAdding code coverage instrumentation.\n');
Expand All @@ -28,7 +30,7 @@ if (OUTPUT_ONLY !== 'true') {

module.exports = (env) => ({
entry: {
app: path.join(SRC_DIR, 'index.tsx'),
app: path.join(SRC_DIR, 'index.ts'),
},
module: {
rules: [
Expand Down Expand Up @@ -171,9 +173,10 @@ module.exports = (env) => ({
output: {
filename: '[name].bundle.js',
path: DIST_DIR,
publicPath: BASE_PATH,
publicPath: 'auto',
},
plugins: [
...moduleFederationPlugins,
...setupWebpackDotenvFilesForEnv({
directory: RELATIVE_DIRNAME,
isRoot: IS_PROJECT_ROOT_DIR,
Expand All @@ -182,7 +185,10 @@ module.exports = (env) => ({
template: path.join(SRC_DIR, 'index.html'),
title: PRODUCT_NAME,
favicon: path.join(SRC_DIR, 'images', FAVICON),
baseUrl: BASE_PATH,
publicPath: BASE_PATH,
base: {
href: BASE_PATH,
},
}),
new CopyPlugin({
patterns: [
Expand Down
8 changes: 1 addition & 7 deletions clients/ui/frontend/config/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,16 @@ module.exports = smp.wrap(
runtimeChunk: 'single',
removeEmptyChunks: true,
},
output: {
filename: '[name].bundle.js',
path: DIST_DIR,
publicPath: BASE_PATH,
},
devServer: {
host: HOST,
port: PORT,
allowedHosts: 'all',
compress: true,
historyApiFallback: true,
hot: true,
open: false,
proxy: [
{
context: ['/api'],
context: ['/api', '/model-registry/api'],
target: {
host: PROXY_HOST,
protocol: PROXY_PROTOCOL,
Expand Down
Loading

0 comments on commit 1e24707

Please sign in to comment.