diff --git a/package.json b/package.json
index 6136ef39df67..c670e232e488 100644
--- a/package.json
+++ b/package.json
@@ -48,10 +48,13 @@
"lodash": "4.17.21"
},
"dependencies": {
- "execa": "8.0.1",
"cssnano": "6.0.3",
+ "execa": "8.0.1",
+ "fast-glob": "3.3.2",
+ "ignore-walk": "6.0.4",
"js-yaml": "4.1.0",
"postcss": "8.4.33",
+ "tar": "6.2.0",
"terser": "5.27.0",
"typescript": "5.3.3"
},
@@ -61,8 +64,8 @@
"cross-env": "7.0.3",
"cypress": "13.6.3",
"eslint": "8.56.0",
- "start-server-and-test": "2.0.3",
- "ncp": "2.0.0"
+ "ncp": "2.0.0",
+ "start-server-and-test": "2.0.3"
},
"optionalDependencies": {
"@tensorflow/tfjs-core": "4.4.0"
diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts
index 8e1a89d55f9a..a5094e6a86a9 100644
--- a/packages/backend/src/server/web/ClientServerService.ts
+++ b/packages/backend/src/server/web/ClientServerService.ts
@@ -51,6 +51,7 @@ const clientAssets = `${_dirname}/../../../../frontend/assets/`;
const assets = `${_dirname}/../../../../../built/_frontend_dist_/`;
const swAssets = `${_dirname}/../../../../../built/_sw_dist_/`;
const viteOut = `${_dirname}/../../../../../built/_vite_/`;
+const tarball = `${_dirname}/../../../../../built/tarball/`;
@Injectable()
export class ClientServerService {
@@ -291,6 +292,13 @@ export class ClientServerService {
decorateReply: false,
});
+ fastify.register(fastifyStatic, {
+ root: tarball,
+ prefix: '/tarball/',
+ immutable: true,
+ decorateReply: false,
+ });
+
fastify.get('/favicon.ico', async (request, reply) => {
return reply.sendFile('/favicon.ico', staticAssets);
});
diff --git a/packages/frontend/src/pages/about.vue b/packages/frontend/src/pages/about.vue
index 69cb6ef647cf..8e5fcda283f9 100644
--- a/packages/frontend/src/pages/about.vue
+++ b/packages/frontend/src/pages/about.vue
@@ -86,6 +86,7 @@ SPDX-License-Identifier: AGPL-3.0-only
nodeinfo
robots.txt
manifest.json
+ source code
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 640713067fcc..64352982643e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -18,12 +18,21 @@ importers:
execa:
specifier: 8.0.1
version: 8.0.1
+ fast-glob:
+ specifier: 3.3.2
+ version: 3.3.2
+ ignore-walk:
+ specifier: 6.0.4
+ version: 6.0.4
js-yaml:
specifier: 4.1.0
version: 4.1.0
postcss:
specifier: 8.4.33
version: 8.4.33
+ tar:
+ specifier: 6.2.0
+ version: 6.2.0
terser:
specifier: 5.27.0
version: 5.27.0
@@ -13488,6 +13497,13 @@ packages:
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
dev: true
+ /ignore-walk@6.0.4:
+ resolution: {integrity: sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==}
+ engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
+ dependencies:
+ minimatch: 9.0.3
+ dev: false
+
/ignore@5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
@@ -19095,6 +19111,18 @@ packages:
mkdirp: 1.0.4
yallist: 4.0.0
+ /tar@6.2.0:
+ resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ chownr: 2.0.0
+ fs-minipass: 2.1.0
+ minipass: 5.0.0
+ minizlib: 2.1.2
+ mkdirp: 1.0.4
+ yallist: 4.0.0
+ dev: false
+
/taskkill@5.0.0:
resolution: {integrity: sha512-+HRtZ40Vc+6YfCDWCeAsixwxJgMbPY4HHuTgzPYH3JXvqHWUlsCfy+ylXlAKhFNcuLp4xVeWeFBUhDk+7KYUvQ==}
engines: {node: '>=14.16'}
diff --git a/scripts/build-assets.mjs b/scripts/build-assets.mjs
index d2dabe85326c..8a8a50d9ba38 100644
--- a/scripts/build-assets.mjs
+++ b/scripts/build-assets.mjs
@@ -12,6 +12,7 @@ import * as terser from 'terser';
import { build as buildLocales } from '../locales/index.js';
import generateDTS from '../locales/generateDTS.js';
import meta from '../package.json' assert { type: "json" };
+import buildTarball from './tarball.mjs';
let locales = buildLocales();
@@ -77,12 +78,13 @@ async function build() {
copyBackendViews(),
buildBackendScript(),
buildBackendStyle(),
+ buildTarball(),
]);
}
await build();
-if (process.argv.includes("--watch")) {
+if (process.argv.includes('--watch')) {
const watcher = fs.watch('./locales');
for await (const event of watcher) {
const filename = event.filename?.replaceAll('\\', '/');
diff --git a/scripts/tarball.mjs b/scripts/tarball.mjs
new file mode 100644
index 000000000000..936a43d27017
--- /dev/null
+++ b/scripts/tarball.mjs
@@ -0,0 +1,32 @@
+import { createWriteStream } from 'node:fs';
+import { mkdir } from 'node:fs/promises';
+import { resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import glob from 'fast-glob';
+import walk from 'ignore-walk';
+import Pack from 'tar/lib/pack.js';
+import meta from '../package.json' assert { type: "json" };
+
+const cwd = fileURLToPath(new URL('..', import.meta.url));
+const ignore = [
+ '**/.git/**/*',
+ '**/*ignore',
+ '**/.gitmodules',
+ // Exclude files you don't want to include in the tarball here
+];
+
+export default async function build() {
+ const mkdirPromise = mkdir(resolve(cwd, 'built', 'tarball'), { recursive: true });
+ const pack = new Pack({ cwd, gzip: true });
+ const patterns = await walk({ path: cwd, ignoreFiles: ['.gitignore'] });
+
+ for await (const entry of glob.stream(patterns, { cwd, ignore, dot: true })) {
+ pack.add(entry);
+ }
+
+ pack.end();
+
+ await mkdirPromise;
+
+ pack.pipe(createWriteStream(resolve(cwd, 'built', 'tarball', `misskey-${meta.version}.tar.gz`)));
+}