Skip to content

Commit

Permalink
web monorepo (#101)
Browse files Browse the repository at this point in the history
* temp

* fix static

* clean up scripts

* unify env var

* fix Dockerfile

* more cleanup

* update readme

* fix tsconfig
  • Loading branch information
dittos authored Sep 11, 2022
1 parent 33e8868 commit 003b624
Show file tree
Hide file tree
Showing 43 changed files with 10,184 additions and 34,713 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: |
mkdir /tmp/extract-static
docker run -v /tmp/extract-static:/workspace --entrypoint /bin/bash animeta-frontend -c "cp -r /app/static /workspace/"
docker run -v /tmp/extract-static:/workspace --entrypoint /bin/bash animeta-frontend -c "cp -r /app/frontend/dist/static /workspace/"
- name: Upload assets
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: gsutil -m cp -z js,css,map -r /tmp/extract-static/static gs://animeta-static/
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,17 @@ PostgreSQL DB에 `schema.sql`을 반영합니다.

### 의존성 설치

npm install
[pnpm](https://pnpm.io/)이 필요합니다.

pnpm install

### 원격 백엔드를 사용하는 경우

프론트엔드만 수정하고 싶을 때 사용할 수 있는 방법입니다. **(주의: 프로덕션 서비스 백엔드를 그대로 사용하게 됩니다.)**

npm run start-remote
pnpm -C frontend run start-remote

### 로컬 백엔드를 사용하는 경우

1. `frontend-server/config.json.sample`을 가지고 `frontend-server/config.json`을 작성합니다.
2. 개발 서버 실행: `npm start`
1. `frontend/config.json.sample`을 가지고 `frontend/config.json`을 작성합니다.
2. 개발 서버 실행: `cd frontend; pnpm start`
9 changes: 3 additions & 6 deletions web/.gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
node_modules
static/build/
frontend/assets.json
frontend-server/config.json
frontend-server/bundle.js*
frontend-dist/
node_modules/
dist/
config.json
stats.json
45 changes: 33 additions & 12 deletions web/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,23 +1,44 @@
FROM node:16 AS builder

RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm

RUN mkdir /app
WORKDIR /app

COPY package.json pnpm-lock.yaml pnpm-workspace.yaml /app/

COPY shared/package.json /app/shared/
COPY frontend-server/package.json /app/frontend-server/
COPY frontend/package.json /app/frontend/

RUN pnpm install --frozen-lockfile

COPY . .
RUN pnpm -C frontend-server run build
RUN pnpm -C frontend run build-assets
RUN pnpm -C frontend run build-server


FROM node:16

RUN curl -f https://get.pnpm.io/v6.16.js | node - add --global pnpm

RUN mkdir /app
WORKDIR /app

COPY package.json package-lock.json /app/
RUN npm ci && npm cache clean --force
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml /app/

COPY shared /app/shared
COPY frontend-server /app/frontend-server
RUN npm run build-dist
RUN cp frontend-server/*.ejs frontend-dist/
COPY shared/package.json /app/shared/
COPY frontend-server/package.json /app/frontend-server/
COPY frontend/package.json /app/frontend/

COPY static /app/static
RUN pnpm -C frontend-server install --frozen-lockfile --prod

COPY frontend /app/frontend
RUN npm run build-assets
RUN npm run build-server
RUN cp frontend/assets.json frontend-server/bundle.js frontend-server/bundle.js.map frontend-dist/
COPY --from=builder /app/shared /app/shared
COPY --from=builder /app/frontend-server /app/frontend-server
COPY --from=builder /app/frontend/dist /app/frontend/dist

ENV NODE_ENV production
ENV ANIMETA_FRONTEND_DIST_PATH /app/frontend/dist

CMD ["node", "frontend-dist/frontendServer.js"]
CMD ["node", "frontend-server/dist/frontendServer.js"]
31 changes: 0 additions & 31 deletions web/frontend-server/frontendServer.js

This file was deleted.

40 changes: 40 additions & 0 deletions web/frontend-server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "@animeta/web-frontend-server",
"private": true,
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "pnpm run clean && tsc --build && cp -r src/views dist/",
"clean": "rm -rf dist/",
"start": "pnpm run build && node dist/frontendServer.js"
},
"devDependencies": {
"@types/cookie-parser": "^1.4.3",
"@types/csurf": "^1.11.2",
"@types/express": "^4",
"@types/express-serve-static-core": "^4.17.30",
"@types/http-proxy": "^1.17.5",
"@types/lodash": "^4.14.165",
"@types/react": "^17.0.46",
"@types/request": "^2.48.3",
"@types/serialize-javascript": "^5.0.0",
"ts-node": "^10.9.1",
"typescript": "^4.8.2"
},
"dependencies": {
"@animeta/web-shared": "workspace:*",
"@sentry/node": "^6.19.7",
"cookie-parser": "^1.4.6",
"csurf": "^1.11.0",
"ejs": "^2.3.4",
"express": "^4.18.1",
"graphql": "^16.6.0",
"graphql-request": "^4.3.0",
"http-proxy": "^1.18.1",
"lodash": "^4.17.21",
"nuri": "github:dittos/nuri-builds#1be420c859a8097bbbfe9e1f7a182954343a7182",
"react": "^17.0.2",
"request": "^2.85.0",
"serialize-javascript": "^1.9.1"
}
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,15 @@ import httpProxy from 'http-proxy';
import serializeJS from 'serialize-javascript';
import isString from 'lodash/isString';
import * as Sentry from '@sentry/node';
import { resolve } from 'path';
import Backend, { HttpNotFound } from './backend';
import renderFeed from './renderFeed';
import { render, ServerRequest } from 'nuri/server';
import { AppProvider } from './lib/core/AppProvider';
import { Loader } from '../shared/loader';
import { ServerRequest } from 'nuri/server';
import { AppProvider } from './AppProvider';
import { Loader } from '@animeta/web-shared/loader';

const config = require(process.env.ANIMETA_CONFIG_PATH || './config.json');
const DEBUG = process.env.NODE_ENV !== 'production';
const MAINTENANCE = process.env.MAINTENANCE;

const backend = new Backend(config.backend.v4BaseUrl, config.backend.v5BaseUrl, config.backend.graphqlUrl);
if (config.sentryDsnNew) {
Sentry.init({ dsn: config.sentryDsnNew });
}

function serializeParams(params: any) {
if (!params) {
return params;
Expand All @@ -34,32 +27,36 @@ function serializeParams(params: any) {
return result;
}

function loaderFactory(serverRequest: ServerRequest): Loader {
return {
callV4(path, params) {
return backend.callV4(serverRequest, path, serializeParams(params));
},
v5: {
call(path: string, params: any, options: any) {
return backend.callV5(serverRequest, path, params);
}
},
getCurrentUser(params) {
return backend.getCurrentUser(serverRequest, serializeParams(params));
},
graphql(doc, variables) {
return backend.graphql(serverRequest, doc, variables);
},
};
}

export function createServer({ server = express(), appProvider, getAssets }: {
server: express.Express;
export function createServer({ config, server = express(), appProvider, getAssets, staticDir }: {
config: any;
server?: express.Express;
appProvider: AppProvider;
getAssets: () => any;
staticDir?: string;
}) {
const backend = new Backend(config.backend.v4BaseUrl, config.backend.v5BaseUrl, config.backend.graphqlUrl);

function loaderFactory(serverRequest: ServerRequest): Loader {
return {
callV4(path, params) {
return backend.callV4(serverRequest, path, serializeParams(params));
},
v5: {
call(path: string, params: any, options: any) {
return backend.callV5(serverRequest, path, params);
}
},
getCurrentUser(params) {
return backend.getCurrentUser(serverRequest, serializeParams(params));
},
graphql(doc, variables) {
return backend.graphql(serverRequest, doc, variables);
},
};
}

server.set('view engine', 'ejs');
server.set('views', __dirname);
server.set('views', __dirname + '/views');
server.set('strict routing', true);
server.set('etag', false);

Expand All @@ -68,10 +65,9 @@ export function createServer({ server = express(), appProvider, getAssets }: {
}
if (config.staticUrl) {
server.use('/static', (req, res) => res.redirect(config.staticUrl + req.path));
} else {
server.use('/static', express.static('static'));
} else if (staticDir) {
server.use('/static', express.static(staticDir));
}
server.get('/mockServiceWorker.js', (req, res) => res.sendFile(resolve(__dirname, '../static/mockServiceWorker.js')))
server.use(cookieParser());

// graphql route should go before csurf middlware (FIXME when start using mutations)
Expand Down
39 changes: 39 additions & 0 deletions web/frontend-server/src/frontendServer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import fs from 'fs';
import path from 'path';
import * as Sentry from '@sentry/node';
import { createServer } from './frontend';
import { DefaultAppProvider } from './AppProvider';

const config = JSON.parse(fs.readFileSync(process.env.ANIMETA_CONFIG_PATH || './config.json', {encoding: 'utf8'}));
if (config.sentryDsnNew) {
Sentry.init({ dsn: config.sentryDsnNew });
}

const port = process.env.PORT || 3000;

const appProvider = new DefaultAppProvider(path.join(process.env.ANIMETA_FRONTEND_DIST_PATH, 'bundle.server.js'));
const assets = JSON.parse(fs.readFileSync(path.join(process.env.ANIMETA_FRONTEND_DIST_PATH, 'assets.json'), {encoding: 'utf8'}));

const server = createServer({
config,
appProvider,
getAssets: () => assets,
staticDir: path.join(process.env.ANIMETA_FRONTEND_DIST_PATH, 'static'),
}).listen(port, () => {
console.log('Server running at port', port);
});

function handleSignal(signal: string) {
console.info(`Got ${signal}.`, new Date().toISOString());
server.close((err) => {
if (err) {
console.error(err);
process.exit(1);
} else {
process.exit();
}
});
}

process.on('SIGINT', handleSignal);
process.on('SIGTERM', handleSignal);
2 changes: 2 additions & 0 deletions web/frontend-server/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export {createServer} from './frontend'
export {evalCode, AppProvider, AppModule} from './AppProvider'
File renamed without changes.
File renamed without changes.
File renamed without changes.
8 changes: 3 additions & 5 deletions web/frontend-server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"compilerOptions": {
"outDir": "../frontend-dist/",
"outDir": "./dist/",
"declaration": true,
"noImplicitAny": true,
"module": "commonjs",
"esModuleInterop": true,
Expand All @@ -14,10 +15,7 @@
]
},
"include": [
"./**/*",
],
"exclude": [
"bundle.js"
"./src/**/*"
],
"references": [
{ "path": "../shared" }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import webpack from 'webpack';
import MemoryFileSystem from 'memory-fs';
import { evalCode, AppProvider, AppModule } from '../core/AppProvider';
const webpack = require('webpack');
const MemoryFileSystem = require('memory-fs');
const {evalCode} = require('@animeta/web-frontend-server');

export class CompilingAppProvider implements AppProvider {
private compiler: webpack.Compiler;
private vfs: MemoryFileSystem;
private bundleFilename: string;
private mod: AppModule;

constructor(webpackConfig: webpack.Configuration) {
class CompilingAppProvider {
constructor(webpackConfig) {
this.compiler = webpack(webpackConfig);
this.vfs = new MemoryFileSystem();
this.compiler.outputFileSystem = this.vfs;
this.bundleFilename = webpackConfig.output.filename;
}

start(): Promise<void> {
start() {
return new Promise((resolve, reject) => {
this.compiler.run((err) => {
if (err) {
Expand All @@ -38,7 +33,7 @@ export class CompilingAppProvider implements AppProvider {
return this.mod;
}

private reloadApp() {
reloadApp() {
const code = this.vfs.readFileSync('/' + this.bundleFilename).toString('utf8');
try {
this.mod = evalCode(code);
Expand All @@ -47,3 +42,5 @@ export class CompilingAppProvider implements AppProvider {
}
}
}

module.exports = {CompilingAppProvider};
8 changes: 4 additions & 4 deletions web/codegen.yaml → web/frontend/codegen.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
schema: ../backend-ts/src/schema.graphql
documents: 'frontend/js/**/*.graphql'
schema: ../../backend-ts/src/schema.graphql
documents: './js/**/*.graphql'
generates:
./frontend/js/__generated__/globalTypes.ts:
./js/__generated__/globalTypes.ts:
plugins:
- typescript
config:
constEnums: true
avoidOptionals: true
./frontend/js:
./js:
preset: near-operation-file
presetConfig:
folder: __generated__
Expand Down
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 003b624

Please sign in to comment.