Просмотр исходного кода

launch next with custom server

Yuki Takei 3 лет назад
Родитель
Сommit
84e4bc7ad2

+ 4 - 8
packages/app/package.json

@@ -4,8 +4,8 @@
   "license": "MIT",
   "scripts": {
     "//// for production": "",
-    "build": "next build",
-    "start": "next start",
+    "build": "yarn next build",
+    "start": "yarn next start",
     "//// for production (obsolete)": "",
     "start:obsolete": "yarn build && yarn server",
     "build:obsolete": "run-p build:*",
@@ -19,12 +19,8 @@
     "preserver": "yarn cross-env NODE_ENV=production yarn migrate",
     "migrate": "node -r dotenv-flow/config node_modules/.bin/migrate-mongo up",
     "//// for development": "",
-    "dev": "next dev",
-    "dev:client": "yarn cross-env NODE_ENV=development webpack --config config/webpack.dev.js --progress --watch",
-    "dev:client:nowatch": "yarn cross-env NODE_ENV=development webpack --config config/webpack.dev.js",
-    "dev:server": "yarn cross-env NODE_ENV=development ts-node-dev --inspect -r tsconfig-paths/register -r dotenv-flow/config --transpile-only src/server/app.ts",
-    "predev:client": "yarn cross-env NODE_ENV=development run-p resources:*",
-    "predev:server": "yarn cross-env NODE_ENV=development yarn dev:migrate:up",
+    "dev": "yarn cross-env NODE_ENV=development ts-node-dev -r tsconfig-paths/register -r dotenv-flow/config --transpile-only src/server/app.ts",
+    "predev": "yarn cross-env NODE_ENV=development run-p resources:* dev:migrate:up",
     "dev:migrate-mongo": "yarn cross-env NODE_ENV=development yarn ts-node node_modules/.bin/migrate-mongo",
     "dev:migrate": "yarn dev:migrate:up",
     "dev:migrate:create": "yarn dev:migrate-mongo create",

+ 7 - 19
packages/app/pages/index.tsx

@@ -1,7 +1,7 @@
-import type { NextPage } from 'next'
-import Head from 'next/head'
-import Image from 'next/image'
-import styles from '../styles/Home.module.css'
+import type { NextPage } from 'next';
+import Head from 'next/head';
+
+import styles from '../styles/Home.module.css';
 
 const Home: NextPage = () => {
   return (
@@ -53,20 +53,8 @@ const Home: NextPage = () => {
         </div>
       </main>
 
-      <footer className={styles.footer}>
-        <a
-          href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
-          target="_blank"
-          rel="noopener noreferrer"
-        >
-          Powered by{' '}
-          <span className={styles.logo}>
-            <Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
-          </span>
-        </a>
-      </footer>
     </div>
-  )
-}
+  );
+};
 
-export default Home
+export default Home;

+ 35 - 27
packages/app/src/server/crowi/dev.js

@@ -3,6 +3,8 @@ import path from 'path';
 import { allLocales } from '~/next-i18next.config';
 import loggerFactory from '~/utils/logger';
 
+import nextFactory from '../routes/next';
+
 const onHeaders = require('on-headers');
 const swig = require('swig-templates');
 
@@ -93,35 +95,41 @@ class CrowiDev {
    * @param {any} app express
    */
   setupExpressAfterListening(app) {
-    this.setupHeaderDebugger(app);
-    this.setupBrowserSync(app);
+    // this.setupHeaderDebugger(app);
+    // this.setupBrowserSync(app);
+    this.setupNextjsStackFrame(app);
   }
 
-  setupHeaderDebugger(app) {
-    logger.debug('setupHeaderDebugger');
-
-    app.use((req, res, next) => {
-      onHeaders(res, () => {
-        logger.debug('HEADERS GOING TO BE WRITTEN');
-      });
-      next();
-    });
-  }
-
-  setupBrowserSync(app) {
-    logger.debug('setupBrowserSync');
-
-    const browserSync = require('browser-sync');
-    const bs = browserSync.create().init({
-      logSnippet: false,
-      notify: false,
-      files: [
-        `${this.crowi.viewsDir}/**/*.html`,
-        `${this.crowi.publicDir}/**/*.js`,
-        `${this.crowi.publicDir}/**/*.css`,
-      ],
-    });
-    app.use(require('connect-browser-sync')(bs));
+  // setupHeaderDebugger(app) {
+  //   logger.debug('setupHeaderDebugger');
+
+  //   app.use((req, res, next) => {
+  //     onHeaders(res, () => {
+  //       logger.debug('HEADERS GOING TO BE WRITTEN');
+  //     });
+  //     next();
+  //   });
+  // }
+
+  // setupBrowserSync(app) {
+  //   logger.debug('setupBrowserSync');
+
+  //   const browserSync = require('browser-sync');
+  //   const bs = browserSync.create().init({
+  //     logSnippet: false,
+  //     notify: false,
+  //     files: [
+  //       `${this.crowi.viewsDir}/**/*.html`,
+  //       `${this.crowi.publicDir}/**/*.js`,
+  //       `${this.crowi.publicDir}/**/*.css`,
+  //     ],
+  //   });
+  //   app.use(require('connect-browser-sync')(bs));
+  // }
+
+  setupNextjsStackFrame(app) {
+    const next = nextFactory(this.crowi);
+    app.get('/__nextjs_original-stack-frame', next.delegateToNext);
   }
 
 }

+ 7 - 3
packages/app/src/server/crowi/index.js

@@ -1,12 +1,11 @@
 /* eslint-disable @typescript-eslint/no-this-alias */
-
 import http from 'http';
 import path from 'path';
 
 import { createTerminus } from '@godaddy/terminus';
 import { initMongooseGlobalSettings, getMongoUri, mongoOptions } from '@growi/core';
 import mongoose from 'mongoose';
-
+import next from 'next';
 
 import pkg from '^/package.json';
 
@@ -426,8 +425,13 @@ Crowi.prototype.getTokens = function() {
 };
 
 Crowi.prototype.start = async function() {
+  const dev = process.env.NODE_ENV !== 'production';
+  this.nextApp = next({ dev });
+
+  await this.nextApp.prepare();
+
   // init CrowiDev
-  if (this.node_env === 'development') {
+  if (dev) {
     const CrowiDev = require('./dev');
     this.crowiDev = new CrowiDev(this);
     this.crowiDev.init();

+ 8 - 3
packages/app/src/server/routes/index.js

@@ -12,6 +12,7 @@ import {
 
 import * as allInAppNotifications from './all-in-app-notifications';
 import * as forgotPassword from './forgot-password';
+import nextFactory from './next';
 import * as privateLegacyPages from './private-legacy-pages';
 import * as userActivation from './user-activation';
 
@@ -54,6 +55,8 @@ module.exports = function(crowi, app) {
   const hackmd = require('./hackmd')(crowi, app);
   const ogp = require('./ogp')(crowi);
 
+  const next = nextFactory(crowi);
+
   const unavailableWhenMaintenanceMode = generateUnavailableWhenMaintenanceModeMiddleware(crowi);
   const unavailableWhenMaintenanceModeForApi = generateUnavailableWhenMaintenanceModeMiddlewareForApi(crowi);
 
@@ -71,7 +74,9 @@ module.exports = function(crowi, app) {
   // API v3 for auth
   app.use('/_api/v3', apiV3AuthRouter);
 
-  app.get('/'                         , applicationInstalled, unavailableWhenMaintenanceMode, loginRequired, autoReconnectToSearch, injectUserUISettings, page.showTopPage);
+  app.get('/_next/*'                  , next.delegateToNext);
+
+  app.get('/'                         , applicationInstalled, unavailableWhenMaintenanceMode, loginRequired, autoReconnectToSearch, injectUserUISettings, next.delegateToNext);
 
   app.get('/login/error/:reason'      , applicationInstalled, login.error);
   app.get('/login'                    , applicationInstalled, login.preLogin, login.login);
@@ -241,7 +246,7 @@ module.exports = function(crowi, app) {
 
   app.get('/:id([0-9a-z]{24})'       , loginRequired , injectUserUISettings, page.showPage);
 
-  app.get('/*/$'                   , loginRequired , injectUserUISettings, page.redirectorWithEndOfSlash);
-  app.get('/*'                     , loginRequired , autoReconnectToSearch, injectUserUISettings, page.redirector);
+  app.get('/*/$'                   , loginRequired , injectUserUISettings, next.delegateToNext);
+  app.get('/*'                     , loginRequired , autoReconnectToSearch, injectUserUISettings, next.delegateToNext);
 
 };

+ 29 - 0
packages/app/src/server/routes/next.ts

@@ -0,0 +1,29 @@
+import {
+  Request, Response,
+} from 'express';
+
+type Crowi = {
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  nextApp: any,
+}
+
+type CrowiReq = Request & {
+  crowi: Crowi,
+}
+
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+export default (crowi: Crowi) => {
+
+  const { nextApp } = crowi;
+  const handle = nextApp.getRequestHandler();
+
+  const delegateToNext = (req: CrowiReq, res: Response): void => {
+    req.crowi = crowi;
+    return handle(req, res);
+  };
+
+  return {
+    delegateToNext,
+  };
+
+};