build: Refine server build steps

This commit is contained in:
Maksim Eltyshev
2025-11-28 17:45:31 +01:00
parent 68e5c33418
commit fedee157c7
10 changed files with 159 additions and 42 deletions

View File

@@ -1,34 +1,34 @@
*/README.md
*/.gitignore
*/node_modules
**/.DS_Store
server/**/.gitkeep
*/node_modules
server/swagger.json
server/.env
server/.editorconfig
server/.eslintignore
server/.npmrc
server/test
server/dist
server/logs
server/.venv
server/test
server/.tmp
server/.venv
server/views/*
!server/views/.gitkeep
server/public/*
!server/public/preloaded-favicons
!server/public/favicons
server/public/favicons/*
!server/public/favicons/.gitkeep
!server/public/user-avatars
server/public/user-avatars/*
!server/public/user-avatars/.gitkeep
!server/public/background-images
server/public/background-images/*
!server/public/background-images/.gitkeep
server/private/*
!server/private/attachments
server/private/attachments/*
!server/private/attachments/.gitkeep
client/dist

View File

@@ -21,6 +21,14 @@ jobs:
- name: Update npm
run: npm install npm --global
- name: Install server dependencies
run: npm install --omit=prod --ignore-scripts
working-directory: ./server
- name: Build server
run: npm run build
working-directory: ./server
- name: Install client dependencies
run: npm install --omit=dev
working-directory: ./client
@@ -29,24 +37,25 @@ jobs:
run: DISABLE_ESLINT_PLUGIN=true npm run build
working-directory: ./client
- name: Include server into dist
run: mv server dist
- name: Include licenses into dist
run: |
mv LICENSE.md server/dist
mv "LICENSES/PLANKA Community License DE.md" server/dist/LICENSE_DE.md
- name: Include built client into dist
run: |
mv dist/* ../dist/public
cp ../dist/public/index.html ../dist/views
working-directory: ./client
- name: Include LICENSE.md, README.md, SECURITY.md into dist
run: mv LICENSE.md README.md SECURITY.md dist
mv ../../client/dist/* public
cp public/index.html views
working-directory: ./server/dist
- name: Create release package
run: |
mv dist planka
zip -r planka-prebuild.zip planka
working-directory: ./server
- name: Publish release package
run: gh release upload ${{ github.event.release.tag_name }} planka-prebuild.zip
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload ${{ github.event.release.tag_name }} planka-prebuild.zip
working-directory: ./server

4
.gitignore vendored
View File

@@ -1,9 +1,9 @@
node_modules
docker-compose.override.yml
.idea
.DS_Store
node_modules
# Prevent another lockfile than package-lock.json (npm) from being created
# If some case you are using pnpm or yarn, don't forget to generate npm lockfile
# before commiting your code by running:

View File

@@ -1,16 +1,19 @@
FROM node:22-alpine AS server-dependencies
# Stage 1: Server build
FROM node:22-alpine AS server
RUN apk -U upgrade \
&& apk add build-base python3 --no-cache
WORKDIR /app
COPY server/package.json server/package-lock.json server/requirements.txt ./
COPY server/patches ./patches
COPY server .
RUN npm install npm --global \
&& npm install --omit=dev
&& npm install \
&& npm run build \
&& npm prune --production
# Stage 2: Client build
FROM node:22 AS client
WORKDIR /app
@@ -18,10 +21,10 @@ WORKDIR /app
COPY client .
RUN npm install npm --global \
&& npm install --omit=dev
RUN DISABLE_ESLINT_PLUGIN=true npm run build
&& npm install --omit=dev \
&& DISABLE_ESLINT_PLUGIN=true npm run build
# Stage 3: Final image
FROM node:22-alpine
RUN apk -U upgrade \
@@ -31,18 +34,20 @@ RUN apk -U upgrade \
USER node
WORKDIR /app
COPY --chown=node:node server .
COPY --chown=node:node LICENSE.md .
COPY --chown=node:node ["LICENSES/PLANKA Community License DE.md", "LICENSE_DE.md"]
COPY --from=server --chown=node:node /app/node_modules node_modules
COPY --from=server --chown=node:node /app/dist .
COPY --from=client --chown=node:node /app/dist public
COPY --from=client --chown=node:node /app/dist/index.html views
RUN python3 -m venv .venv \
&& .venv/bin/pip3 install -r requirements.txt --no-cache-dir \
&& mv .env.sample .env \
&& npm config set update-notifier false
COPY --from=server-dependencies --chown=node:node /app/node_modules node_modules
COPY --from=client --chown=node:node /app/dist public
COPY --from=client --chown=node:node /app/dist/index.html views
VOLUME /app/public/favicons
VOLUME /app/public/user-avatars
VOLUME /app/public/background-images

View File

@@ -12,6 +12,7 @@
"postinstall": "npm i --prefix server && npm i --prefix client",
"lint": "npm run server:lint && npm run client:lint",
"prepare": "husky",
"server:build": "npm run build --prefix server",
"server:console": "npm run console --prefix server",
"server:db:create-admin-user": "npm run db:create-admin-user --prefix server",
"server:db:init": "npm run db:init --prefix server",

36
server/.buildignore Normal file
View File

@@ -0,0 +1,36 @@
**/.gitkeep
**/.DS_Store
build.js
generate-swagger.js
nodemon.json
swagger.json
version-template.ejs
.buildignore
.editorconfig
.env
.eslintignore
.gitignore
.npmrc
.tmp
.venv
dist
logs
node_modules
test
views/*
public/*
!public/preloaded-favicons
!public/favicons
public/favicons/*
!public/user-avatars
public/user-avatars/*
!public/background-images
public/background-images/*
private/*
!private/attachments
private/attachments/*

11
server/.gitignore vendored
View File

@@ -131,6 +131,12 @@ lib-cov
swagger.json
dist
logs
views/*
!views/.gitkeep
public/*
!public/preloaded-favicons
!public/favicons
@@ -147,8 +153,3 @@ private/*
!private/attachments
private/attachments/*
!private/attachments/.gitkeep
views/*
!views/.gitkeep
logs

42
server/build.js Normal file
View File

@@ -0,0 +1,42 @@
const fs = require('fs');
const path = require('path');
// eslint-disable-next-line import/no-extraneous-dependencies
const ignore = require('ignore');
const OUT_DIR = 'dist';
const ig = ignore();
if (fs.existsSync('.buildignore')) {
const patterns = fs.readFileSync('.buildignore', 'utf8');
ig.add(patterns);
}
if (fs.existsSync(OUT_DIR)) {
fs.rmSync(OUT_DIR, { recursive: true, force: true });
}
fs.mkdirSync(OUT_DIR, { recursive: true });
const build = (src, dest) => {
const dirents = fs.readdirSync(src, { withFileTypes: true });
// eslint-disable-next-line no-restricted-syntax
for (const dirent of dirents) {
const srcPath = path.join(src, dirent.name);
if (ig.ignores(srcPath)) {
continue; // eslint-disable-line no-continue
}
const destPath = path.join(dest, dirent.name);
if (dirent.isDirectory()) {
fs.mkdirSync(destPath, { recursive: true });
build(srcPath, destPath);
} else {
fs.copyFileSync(srcPath, destPath);
}
}
};
build('./', OUT_DIR);

View File

@@ -48,6 +48,7 @@
"eslint-config-prettier": "^9.1.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.4",
"ignore": "^7.0.5",
"mocha": "^10.8.2",
"nodemon": "^3.1.11",
"prettier": "3.3.3",
@@ -1108,6 +1109,16 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/eslintrc/node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/@eslint/js": {
"version": "8.57.1",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
@@ -4784,6 +4795,16 @@
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint/node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/esm": {
"version": "3.2.25",
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
@@ -6015,9 +6036,9 @@
}
},
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"version": "7.0.5",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
"integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
"dev": true,
"license": "MIT",
"engines": {

View File

@@ -3,6 +3,7 @@
"private": true,
"main": "app.js",
"scripts": {
"build": "node build.js",
"console": "dotenv sails console",
"db:create-admin-user": "node db/create-admin-user.js",
"db:init": "node db/init.js",
@@ -84,6 +85,7 @@
"eslint-config-prettier": "^9.1.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.4",
"ignore": "^7.0.5",
"mocha": "^10.8.2",
"nodemon": "^3.1.11",
"prettier": "3.3.3",