diff --git a/.env b/.env deleted file mode 100644 index 786c4376..00000000 --- a/.env +++ /dev/null @@ -1,2 +0,0 @@ -REACT_APP_API_HOST=https://v2dev.velog.io/ -PUBLIC_URL=https://static.velog.io/ \ No newline at end of file diff --git a/.env.development b/.env.development new file mode 100644 index 00000000..c370e8e7 --- /dev/null +++ b/.env.development @@ -0,0 +1,7 @@ +PUBLIC_URL=/ + +REACT_APP_CLIENT_V3_HOST=http://localhost:3001 +REACT_APP_API_HOST=http://localhost:5002/ + +REACT_APP_GRAPHQL_HOST=http://localhost:5002/ +REACT_APP_GRAPHQL_HOST_NOCDN=https://v2.velog.io/ \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 00000000..034cf768 --- /dev/null +++ b/.env.production @@ -0,0 +1,7 @@ +PUBLIC_URL=/ + +REACT_APP_CLIENT_V3_HOST=http://localhost:3001 +REACT_APP_API_HOST=http://localhost:5002/ + +REACT_APP_GRAPHQL_HOST=https://v2cdn.velog.io/ +REACT_APP_GRAPHQL_HOST_NOCDN=https://v2.velog.io/ \ No newline at end of file diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 3d0f76c5..2a95e2f9 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -28,7 +28,7 @@ jobs: - name: npm run build:ci run: npm run build:ci env: - REACT_APP_API_HOST: 'https://v2dev.velog.io/' + REACT_APP_API_HOST: 'https://v2.velog.io/' PUBLIC_URL: 'https://d3v0gm8v6v8olv.cloudfront.net/' STAGE: true - name: s3 sync @@ -50,7 +50,7 @@ jobs: # or if using AWS creds directly AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }} - REACT_APP_API_HOST: 'https://v2dev.velog.io/' + REACT_APP_API_HOST: 'https://v2.velog.io/' PUBLIC_URL: 'https://d3v0gm8v6v8olv.cloudfront.net/' STAGE: true - name: Slack Notification diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 62e9ebcf..660d8f68 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,4 +1,4 @@ -name: Deploy Serverless SSR +name: Deploy on: push: @@ -11,55 +11,42 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@master + - name: Setup Node.js 16.x + uses: actions/setup-node@v2 + with: + node-version: '16.x' - name: Get yarn cache id: yarn-cache run: echo "::set-output name=dir::$(yarn cache dir)" - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + key: ${{ runner.os }}-yarn-v1-${{ hashFiles('**/yarn.lock') }} restore-keys: | ${{ runner.os }}-yarn- - name: yarn install - uses: borales/actions-yarn@v2.0.0 + uses: borales/actions-yarn@v4.0.0 with: cmd: install - name: npm run build:ci run: npm run build:ci env: REACT_APP_API_HOST: 'https://v2.velog.io/' + REACT_APP_GRAPHQL_HOST: 'https://v2.velog.io/' + REACT_APP_GRAPHQL_HOST_NOCDN: 'https://v2.velog.io/' PUBLIC_URL: 'https://static.velog.io/' - - name: s3 sync - uses: jakejarvis/s3-sync-action@master - with: - args: --follow-symlinks --delete + REACT_APP_REDIS_HOST: ${{ secrets.REDIS_HOST }} + REACT_APP_CLIENT_V3_HOST: 'https://velog.io/' + REACT_APP_WHITELIST_IPS: ${{ secrets.REACT_APP_WHITELIST_IPS }} + CI: false + - name: upload env: - AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} + S3_BUCKET_SSR: ${{ secrets.AWS_S3_BUCKET_SSR }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }} AWS_REGION: 'ap-northeast-2' - SOURCE_DIR: 'build' - - - name: serverless deploy - uses: serverless/github-action@master - with: - args: deploy --stage production - env: - # or if using AWS creds directly - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_KEY }} - REACT_APP_API_HOST: 'https://v2.velog.io/' - PUBLIC_URL: 'https://static.velog.io/' - - name: Deploy Completion Webhook - uses: joelwmale/webhook-action@master - env: - WEBHOOK_URL: ${{ secrets.SSR_COMPLETE_WEBHOOK }} - data: "{'deployment': 'finished'}" - - name: Slack Notification - uses: rtCamp/action-slack-notify@v2.0.0 - env: - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} - SLACK_USERNAME: 'Github Actions' - SLACK_ICON: 'https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png' - SLACK_MESSAGE: '*stage: production* - 벨로그 웹 클라이언트 배포가 끝났어요! :rocket:' \ No newline at end of file + run: | + yarn upload + yarn upload:ssr \ No newline at end of file diff --git a/.gitignore b/.gitignore index c70b7cf4..0516f767 100755 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,8 @@ jspm_packages # Serverless directories .serverless -.webpack \ No newline at end of file +.webpack + +# ignore setting +.idea +.vscode diff --git a/asset-license.md b/asset-license.md index 2f1b50c6..db7d2bd0 100644 --- a/asset-license.md +++ b/asset-license.md @@ -8,4 +8,4 @@ Icons made by [Smashicons](https://www.flaticon.com/authors/smashicons) from [ww Heart Icon: https://iconmonstr.com/favorite-8-svg/ Clip Icon: https://iconmonstr.com/paperclip-2-svg/ - +Check Icon: https://iconmonstr.com/check-mark-1-svg/ \ No newline at end of file diff --git a/config/webpack.config.server.js b/config/webpack.config.server.js index 9d975f25..2728133f 100644 --- a/config/webpack.config.server.js +++ b/config/webpack.config.server.js @@ -130,8 +130,8 @@ module.exports = { resolve: { modules: ['node_modules'], extensions: paths.moduleFileExtensions - .map(ext => `.${ext}`) - .filter(ext => true || !ext.includes('ts')), + .map((ext) => `.${ext}`) + .filter((ext) => true || !ext.includes('ts')), }, plugins: [ new webpack.DefinePlugin(env.stringified), @@ -139,6 +139,10 @@ module.exports = { /codemirror/, path.resolve(paths.appSrc, 'lib/replacedModule.ts'), ), + new webpack.NormalModuleReplacementPlugin( + /lib\/graphql\/client/, + path.resolve(paths.appSrc, 'lib/replacedModule.ts'), + ), new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }), ], optimization: { diff --git a/deploy.config.json b/deploy.config.json new file mode 100644 index 00000000..343bbbf8 --- /dev/null +++ b/deploy.config.json @@ -0,0 +1,13 @@ +{ + "apps": [ + { + "name": "ssr", + "script": "./dist/server.js", + "instances": 2, + "exec_mode": "cluster", + "env": { + "NODE_PATH": "src" + } + } + ] +} \ No newline at end of file diff --git a/docker/redis/docker-compose.yml b/docker/redis/docker-compose.yml index ca92b923..a67981a5 100644 --- a/docker/redis/docker-compose.yml +++ b/docker/redis/docker-compose.yml @@ -6,7 +6,6 @@ services: environment: # ALLOW_EMPTY_PASSWORD is recommended only for development. - ALLOW_EMPTY_PASSWORD=yes - - REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL ports: - '6379:6379' volumes: diff --git a/package.json b/package.json index 95a5c64d..eb77c765 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,10 @@ "@apollo/react-testing": "^3.1.3", "@babel/core": "7.7.4", "@koa/router": "^8.0.5", - "@loadable/babel-plugin": "^5.11.0", - "@loadable/component": "^5.11.0", - "@loadable/server": "^5.11.0", + "@loadable/babel-plugin": "^5.13.2", + "@loadable/component": "^5.15.0", + "@loadable/server": "^5.15.1", + "@react-spring/web": "^9.4.2", "@reduxjs/toolkit": "^1.2.2", "@sentry/browser": "^5.11.1", "@svgr/webpack": "4.3.3", @@ -25,6 +26,7 @@ "@types/jest": "^24.0.0", "@types/koa": "^2.11.0", "@types/koa-bodyparser": "^4.3.0", + "@types/koa-compress": "^4.0.6", "@types/koa-static": "^4.0.1", "@types/koa__router": "^8.0.2", "@types/loadable__component": "^5.10.0", @@ -44,10 +46,12 @@ "@types/react-router-dom": "^5.1.3", "@types/react-textarea-autosize": "^4.3.5", "@types/react-toastify": "^4.1.0", - "@types/styled-components": "^4.4.1", + "@types/react-virtualized": "^9.21.8", + "@types/sanitize-html": "^1.20.2", + "@types/styled-components": "^5.1.21", "@types/throttle-debounce": "^2.1.0", - "@typescript-eslint/eslint-plugin": "^2.8.0", - "@typescript-eslint/parser": "^2.8.0", + "@typescript-eslint/eslint-plugin": "^4.1.1", + "@typescript-eslint/parser": "^4.1.1", "apollo-boost": "^0.4.7", "apollo-link": "^1.2.13", "aws-lambda": "^1.0.4", @@ -88,9 +92,12 @@ "jest-environment-jsdom-fourteen": "0.1.0", "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", + "just-detect-adblock": "^1.1.0", + "katex": "^0.11.1", "koa": "^2.11.0", "koa-better-http-proxy": "^0.2.4", "koa-bodyparser": "^4.2.1", + "koa-compress": "^5.1.1", "koa-static": "^5.0.0", "mini-css-extract-plugin": "0.8.0", "node-fetch": "^2.6.0", @@ -115,31 +122,38 @@ "react-outside-click-handler": "^1.3.0", "react-redux": "^7.1.3", "react-router-dom": "^5.1.2", - "react-spring": "^8.0.27", + "react-spring": "^9.4.2", "react-textarea-autosize": "^7.1.2", "react-toastify": "^5.5.0", "react-use": "^13.12.2", + "react-virtualized": "^9.21.2", "redux": "^4.0.4", "redux-devtools-extension": "^2.13.8", + "rehype-katex": "^3.0.0", + "rehype-raw": "^4.0.2", + "rehype-stringify": "^6.0.1", "remark": "^11.0.2", - "remark-breaks": "^1.0.3", + "remark-breaks": "^2.0.1", "remark-highlight.js": "^5.2.0", "remark-html": "^10.0.0", + "remark-math": "^2.0.1", + "remark-rehype": "^6.0.0", "remark-slug": "^5.1.2", "resolve": "1.12.2", "resolve-url-loader": "3.1.1", + "sanitize-html": "^1.21.1", "sass-loader": "8.0.0", "semver": "6.3.0", "serverless-webpack": "^5.3.1", "snakecase-keys": "^3.1.0", "strip-markdown": "^3.1.1", "style-loader": "1.0.0", - "styled-components": "^4.4.1", + "styled-components": "^5.3.3", "terser-webpack-plugin": "2.2.1", "throttle-debounce": "^2.1.0", "ts-pnp": "1.1.5", "typesafe-actions": "^5.1.0", - "typescript": "~3.7.2", + "typescript": "^4.5.5", "unist-util-visit": "^2.0.1", "url-loader": "2.3.0", "webpack": "4.41.2", @@ -149,13 +163,16 @@ "workbox-webpack-plugin": "4.3.1" }, "scripts": { - "start": "node scripts/start.js", + "start": "node scripts/start.js --max-http-header-size=1024", "build": "node scripts/build.js", - "build:ci": "node scripts/build.js && node scripts/keepChunks.js", + "build:ci": "node scripts/build.js && node scripts/build.server.js", "build:server": "node scripts/build.server.js", "start:server:local": "node ./dist/server.js", "test": "node scripts/test.js", - "upload:s3": "aws s3 sync ./build s3://$S3_BUCKET --delete" + "upload": "aws s3 cp --recursive ./build s3://$S3_BUCKET", + "upload:ssr": "aws s3 cp --recursive ./dist s3://$S3_BUCKET_SSR", + "download": "aws s3 cp s3://$S3_BUCKET ./build/ --recursive && aws s3 cp s3://$S3_BUCKET_SSR ./dist/ --recursive", + "deploy": "pm2 reload deploy.config.json" }, "eslintConfig": { "extends": [ @@ -233,8 +250,8 @@ "@loadable/babel-plugin" ] }, - "proxy": "http://localhost:5000/", + "proxy": "https://v2.velog.io/", "devDependencies": { - "@loadable/webpack-plugin": "^5.7.1" + "@loadable/webpack-plugin": "^5.15.1" } } diff --git a/public/index.html b/public/index.html index e681d654..d2a80421 100644 --- a/public/index.html +++ b/public/index.html @@ -29,15 +29,17 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - - + + + + +