vendure-ecommerce / vendure

The commerce platform with customization in its DNA.
https://www.vendure.io
Other
5.58k stars 989 forks source link

Decouple Admin UI and API #3039

Open rafapsm opened 2 weeks ago

rafapsm commented 2 weeks ago

Hi,

I'm working on decoupling the Admin UI and API in our project and deploying them as separate apps on Heroku using the same repository. I have made some changes to the setup, but I encountered issues when trying to deploy. The apps don't seem to run correctly on Heroku.

Here’s what I’ve done so far:

Original Setup: Previously, the AdminUiPlugin was initialized directly in the vendure-config.ts file.

Changes Made:

I moved the initialization logic of the AdminUiPlugin from the vendure-config.ts to a new file named compile-admin-ui.ts. The goal was to separate the build process for the Admin UI from the API, allowing them to be deployed independently.

vendure-config.ts

// Before
(...)
AdminUiPlugin.init({
            route: 'admin',
            port: +(process.env.PORT as string) || 3000,
            app: customAdminUi({ recompile: IS_LOCAL, devMode: IS_LOCAL }),
            adminUiConfig: {
                apiPort: IS_LOCAL ? +(process.env.PORT as string) : undefined,
                brand: 'Backoffice Profissionais',
                hideVersion: true,
                hideVendureBranding: true,
                defaultLanguage: LanguageCode.pt_PT,
                availableLanguages: [LanguageCode.en, LanguageCode.pt_PT],
                loginImageUrl:
                    'https://unsplash.com/photos/l5Tzv1alcps/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNzA2Njk4MzQxfA&force=true&w=640',
            },
        }), 
(...)
// After
(...)
AdminUiPlugin
(...)

compile-admin-ui.ts

import { compileUiExtensions, setBranding } from '@vendure/ui-devkit/compiler';
import path from 'path';
import { promises as fs } from 'fs';
import { UIComponentsPlugin } from './plugins';

async function buildAdminUi() {
    const compiledAppPath = path.join(__dirname, '../admin-ui');

    // Compile the Admin UI if recompile flag is set
    if (process.env.NODE_ENV === 'production') {
        console.log('Building Admin UI for production...');
        await compileUiExtensions({
            outputPath: compiledAppPath,
            extensions: [
                UIComponentsPlugin.uiExtensions,
                {
                    translations: {
                        en: path.join(__dirname, 'translations/en.json'),
                        pt_PT: path.join(__dirname, 'translations/pt_PT.json'),
                    },
                },
                setBranding({
                    smallLogoPath: path.join(__dirname, 'assets/quatru-branding/logo_quatru.png'),
                    largeLogoPath: path.join(__dirname, 'assets/quatru-branding/logo_quatru.png'),
                    faviconPath: path.join(__dirname, 'assets/quatru-branding/fav_icon.png'),
                }),
            ],
            devMode: false,
        });
        console.log('Admin UI built successfully.');
    } else {
        console.log('Serving Admin UI without rebuilding...');
        return {
            path: path.join(compiledAppPath, 'dist'),
        };
    }
}

async function configureForHeroku() {
    const apiHost = process.env.API_HOST || 'http://localhost:3000'; // Default to localhost for local development
    const apiPort = process.env.PORT ? process.env.PORT : undefined;

    if (process.env.BUILD_ADMIN_UI) {
        console.log('Configuring vendure-ui-config.json for Heroku deployment...');
        await fs.writeFile(
            path.join(__dirname, '../admin-ui', 'dist', 'vendure-ui-config.json'),
            JSON.stringify({
                apiHost,
                apiPort,
                adminApiPath: 'admin-api',
                defaultLanguage: 'pt_PT',
                availableLanguages: ['en', 'pt_PT'],
                hideVendureBranding: true,
                hideVersion: true,
                loginImageUrl:
                    'https://unsplash.com/photos/l5Tzv1alcps/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNzA2Njk4MzQxfA&force=true&w=640',
            }),
        );
        console.log('vendure-ui-config.json configured for Heroku.');
    }
}

if (require.main === module) {
    buildAdminUi().then(() => {
        configureForHeroku().then(() => process.exit(0));
    });
}

export function customAdminUi(options: { recompile: boolean; devMode: boolean }) {
    if (options.recompile) {
        return buildAdminUi();
    } else {
        return {
            path: path.join(__dirname, '../admin-ui', 'dist'),
        };
    }
}

I also updated the build scripts in the package.json to ensure they handle the separate build processes for the Admin UI and the API.

package.json

scripts: {
     (...)
    "build": "node build.js",
    "build-admin": "npx ts-node src/compile-admin-ui.ts",
     "start:server": "node ./dist/index.js ",
    "start:worker": "node ./dist/index-worker.js",
    "start": "concurrently npm:start:*",
    "heroku-postbuild": "npm install && npm run build"
     (...)
}

build.js

const { execSync } = require('child_process');

const isAdminUIOnly = process.env.ADMIN_UI_ONLY === 'true';

try {
  if (isAdminUIOnly) {
    console.log('Building Admin UI only...');
    execSync('npm run build-admin', { stdio: 'inherit' });
  } else {
    console.log('Building full application...');
    execSync('npm run clean && tsc && npm run copy-files', { stdio: 'inherit' });
  }
} catch (error) {
  console.error('Error occurred during build process:', error);
  process.exit(1);
}

Despite these changes, when I try to deploy the apps on Heroku, they don't run correctly. It seems like the build and deployment processes are not functioning as intended.

Any insights or advice on how to resolve these issues would be greatly appreciated!

Thank you.

michaelbromley commented 1 week ago

Hi,

Despite these changes, when I try to deploy the apps on Heroku, they don't run correctly.

This is too vague to know what might be the issue. Please exactly define what you mean by "don't run correctly":

rafapsm commented 1 week ago

Hey @michaelbromley !

The error is that dist folder is not being generated. And this happens on both apps (Admin UI and API)

Cannot find module '/app/dist/index-worker.js'
(...)
Error: Cannot find module '/app/dist/index.js'
rafapsm commented 3 days ago

Hi,

Despite these changes, when I try to deploy the apps on Heroku, they don't run correctly.

This is too vague to know what might be the issue. Please exactly define what you mean by "don't run correctly":

  • are there errors logged?
  • do you not get the expected response from API requests?
  • something else?

Hey @michaelbromley !

The error is that dist folder is not being generated. And this happens on both apps (Admin UI and API)

Cannot find module '/app/dist/index-worker.js' (...) Error: Cannot find module '/app/dist/index.js'

michaelbromley commented 3 days ago

can you share a minimal reproduction repo?