Skip to content

Commit 03e3cab

Browse files
kapetrPetrBulanek
andauthored
feat(ui): switch to nextjs (#760)
Signed-off-by: Petr Kadlec <[email protected]> Signed-off-by: Petr Bulánek <[email protected]> Co-authored-by: Petr Bulánek <[email protected]>
1 parent 2572b2d commit 03e3cab

File tree

129 files changed

+1557
-2307
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

129 files changed

+1557
-2307
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Dockerfile
2222

2323
# Node
2424
node_modules
25+
.next
2526

2627
# Misc
2728
dist

.github/workflows/release.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,20 @@ jobs:
109109
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}/beeai-server:cache
110110
cache-to: type=registry,ref=ghcr.io/${{ github.repository }}/beeai-server:cache,mode=max
111111

112+
- uses: docker/build-push-action@v6
113+
with:
114+
context: .
115+
file: ./apps/beeai-ui/Dockerfile
116+
push: true
117+
platforms: linux/amd64,linux/arm64
118+
tags: |
119+
ghcr.io/${{ github.repository }}/beeai-ui:${{ github.sha }}
120+
ghcr.io/${{ github.repository }}/beeai-ui:${{ steps.version.outputs.version }}
121+
ghcr.io/${{ github.repository }}/beeai-ui:${{ steps.version.outputs.latestTag }}
122+
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}/beeai-ui:cache
123+
cache-to: type=registry,ref=ghcr.io/${{ github.repository }}/beeai-ui:cache,mode=max
124+
125+
112126
- run: mise run helm:build
113127
- run: echo '${{ secrets.GITHUB_TOKEN }}' | helm registry login --username '${{ github.actor }}' --password-stdin ghcr.io
114128
- run: helm push ./helm/dist/beeai-platform-*.tgz 'oci://ghcr.io/${{ github.repository }}/beeai-platform-chart'

apps/beeai-ui/.dockerignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Docker
2+
Dockerfile
3+
.dockerignore
4+
5+
# Node
6+
node_modules
7+
.next
8+
9+
# Misc
10+
dist

apps/beeai-ui/.env.example

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1+
API_URL='http://127.0.0.1:8333'
2+
13
############# OPTIONAL #############
24

35
# Default: 'BeeAI'
4-
VITE_APP_NAME=
6+
NEXT_PUBLIC_APP_NAME=
57

68
# Default: '/bee.svg'
7-
VITE_APP_FAVICON_SVG=
8-
9-
# Default: 'http://localhost:8333'
10-
VITE_API_SERVER_TARGET=
9+
NEXT_PUBLIC_APP_FAVICON_SVG=
1110

1211
# Default: 'http://localhost:6006'
13-
VITE_PHOENIX_SERVER_TARGET=
12+
NEXT_PUBLIC_PHOENIX_SERVER_TARGET='http://localhost:6006'
13+
14+
# Custom navigation structure in JSON format
15+
# See ./src/modules/nav/schema.ts for the schema definition
16+
NEXT_PUBLIC_NAV_ITEMS=

apps/beeai-ui/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/.next/

apps/beeai-ui/Dockerfile

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
FROM node:23-alpine AS base
2+
3+
ENV PNPM_HOME="/pnpm"
4+
ENV PATH="$PNPM_HOME:$PATH"
5+
RUN corepack enable pnpm
6+
7+
FROM base AS builder
8+
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
9+
RUN apk add --no-cache libc6-compat
10+
WORKDIR /app
11+
12+
COPY . .
13+
14+
ENV NEXT_TELEMETRY_DISABLED=1
15+
ENV API_URL=http://beeai-platform-svc:8333
16+
17+
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm i --frozen-lockfile
18+
RUN pnpm run --filter=@i-am-bee/beeai-ui build
19+
RUN pnpm deploy --legacy --filter=@i-am-bee/beeai-ui --prod /prod/app
20+
RUN cp -r apps/beeai-ui/.next /prod/app/.next
21+
22+
FROM base AS runner
23+
WORKDIR /opt
24+
25+
ENV NODE_ENV=production
26+
27+
ENV NEXT_TELEMETRY_DISABLED=1
28+
29+
RUN addgroup --system --gid 1001 nodejs
30+
RUN adduser --system --uid 1001 nextjs
31+
32+
# Automatically leverage output traces to reduce image size
33+
# https://nextjs.org/docs/advanced-features/output-file-tracing
34+
COPY --from=builder --chown=nextjs:nodejs /prod/app/.next/standalone ./
35+
36+
WORKDIR /opt/apps/beeai-ui
37+
38+
COPY --from=builder --chown=nextjs:nodejs /prod/app/.next/static ./.next/static
39+
COPY --from=builder /prod/app/public ./public
40+
41+
USER nextjs
42+
43+
EXPOSE 3000
44+
45+
ENV PORT=3000
46+
47+
ENV HOSTNAME="0.0.0.0"
48+
CMD ["node", "server.js"]

apps/beeai-ui/eslint.config.js

Lines changed: 0 additions & 36 deletions
This file was deleted.

apps/beeai-ui/eslint.config.mjs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Copyright 2025 © BeeAI a Series of LF Projects, LLC
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { FlatCompat } from '@eslint/eslintrc';
7+
import { dirname } from 'path';
8+
import { fileURLToPath } from 'url';
9+
10+
const __filename = fileURLToPath(import.meta.url);
11+
const __dirname = dirname(__filename);
12+
13+
const compat = new FlatCompat({
14+
baseDirectory: __dirname,
15+
});
16+
17+
const eslintConfig = [
18+
...compat.extends('next/core-web-vitals', 'next/typescript', 'prettier'),
19+
...compat.plugins('simple-import-sort'),
20+
{
21+
rules: {
22+
'simple-import-sort/imports': 'error',
23+
'simple-import-sort/exports': 'error',
24+
},
25+
},
26+
];
27+
28+
export default eslintConfig;

apps/beeai-ui/index.html

Lines changed: 0 additions & 40 deletions
This file was deleted.

apps/beeai-ui/next.config.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/**
2+
* Copyright 2025 © BeeAI a Series of LF Projects, LLC
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import type { NextConfig } from 'next';
7+
import path from 'path';
8+
9+
const nextConfig: NextConfig = {
10+
output: 'standalone',
11+
sassOptions: {
12+
additionalData: `@use 'styles/common' as *; @use 'sass:math';`,
13+
// silenceDeprecations: ['mixed-decls', 'global-builtin'],
14+
api: 'modern',
15+
implementation: 'sass-embedded',
16+
quietDeps: true,
17+
includePaths: [path.join(__dirname, 'node_modules'), path.join(__dirname, 'src')],
18+
},
19+
webpack(config) {
20+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
21+
const fileLoaderRule = config.module.rules.find((rule: any) => rule.test?.test?.('.svg'));
22+
23+
config.module.rules.push(
24+
// Reapply the existing rule, but only for svg imports ending in ?url
25+
{
26+
...fileLoaderRule,
27+
test: /\.svg$/i,
28+
resourceQuery: /url/, // *.svg?url
29+
},
30+
// Convert all other *.svg imports to React components
31+
{
32+
test: /\.svg$/i,
33+
issuer: fileLoaderRule.issuer,
34+
resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] }, // exclude if *.svg?url
35+
use: [
36+
{
37+
loader: '@svgr/webpack',
38+
options: {
39+
svgoConfig: {
40+
plugins: [
41+
{
42+
name: 'preset-default',
43+
params: {
44+
overrides: {
45+
removeViewBox: false,
46+
},
47+
},
48+
},
49+
],
50+
},
51+
},
52+
},
53+
],
54+
},
55+
);
56+
57+
// Modify the file loader rule to ignore *.svg, since we have it handled now.
58+
fileLoaderRule.exclude = /\.svg$/i;
59+
60+
return config;
61+
},
62+
experimental: {
63+
// Disable CSS chunking due to persistent nextjs bug with ordering of css and this seems to help partially.
64+
// Nextjs in production build only! puts global styles last so it messes up css specificity.
65+
//
66+
// We get css modules styles twice but atleast the second css file overwrites them in correct order.
67+
//
68+
// I think it's actually two issues, first is with sideEffects and external packages, because beeai-ui doesn't
69+
// have `sideEffects: false` in package.json and I don't wanna add it because it's vite app, not a library
70+
// and we have single `index.ts` in it that exports everything, nextjs bundler doesn't tree shake and sees
71+
// all styles as required in a root layout. Having separate exports in package.json helps but doesn't mitigrate
72+
// the issue completely see second issue bellow.
73+
//
74+
// The second issue is IMHO when the same component is imported from the page and layout and from RSC and from
75+
// client component simultaneously, this breaks nextjs and as a result puts global styles after css modules styles.
76+
// In our codebase it's a case of a Container component. I wasn't able to refactor this cleanly hence this workaround
77+
//
78+
// https://github.com/vercel/next.js/issues/68207
79+
// https://github.com/vercel/next.js/issues/64921
80+
cssChunking: false,
81+
},
82+
};
83+
84+
export default nextConfig;

0 commit comments

Comments
 (0)