preface
The React server renders the SSR framework Next. Js, and the Vue server renders the SSR framework nuxt.js.
Why do I need server-side rendering?
-
Reduces the first blank screen time
-
SEO: Search Engine Optimization; To put it simply, when the web page is requested, the content sent from the server can be crawled to the data by the search engine crawler. At this time, the keywords searched from the search engine are included in the content, so the information of the WEBSITE is more easily displayed in the search results
-
Client-side rendering: the appearance of front-end SPA, most of the page content in the browser side through asynchronous request to get data, and then render generation; And from the server is just a shell without content, search engines naturally climb less than things ~
-
Server-side rendering: Previous back-end MCV frameworks used templates to generate content on the server, and then the browser received the data and rendered it directly. This time the content of the web page has followed the site over, the main content does not need additional asynchronous request to obtain, the search engine crawler can climb to these non-asynchronous request data ~
-
SSR of front-end framework: mainly isomorphism of front and back end, aggregation of microservice interface, etc. Of course, just as the rendering layer is the simplest, the interface is taken care of by the backend big guy; React/Vue/Angular have frameworks that use Node.js to render data on the server. The React/Vue/Angular framework can still be used on the front end, but some data is generated on the server side
See the source at 👇 here
As you can see, there is already content when it comes from the server:
Subsequent route changes are equivalent to a single page SPA, but refreshed under a route that is rendered by the server
1. SRC directory structure
. ├ ─ ─ components │ ├ ─ ─ the header │ ├ ─ ─ the hello world - │ └ ─ ─ layout ├ ─ ─ pages │ ├ ─ ─ _app. The TSX │ ├ ─ ─ _error. The TSX │ ├ ─ ─ the about the TSX │ ├ ─ ─ the detail. The TSX │ └ ─ ─ index. The TSX ├ ─ ─ store │ ├ ─ ─ home. Ts │ └ ─ ─ but ts └ ─ ─ styles ├ ─ ─ _error. SCSS ├ ─ ─ the about the SCSS ├ ─ ─ Detail. SCSS └ ─ ─ index. SCSSCopy the code
2, NPM script
TSC needs to be installed
yarn install typescript -g
Copy the code
3, page head
Set page head
import Head from 'next/head';
const Header = (a)= > (
<Head>
<title>Next.js test</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
</Head>
);
Copy the code
It can be used where the page head needs to be changed, for example, /about needs to be changed to about. Incremental modification: If no, add it; if yes, modify it
// ...
<Head>
<title>about</title>
</Head>
// ...
Copy the code
4, routing,
Routes are automatically generated in the Pages directory at only one layer:
// The first way
pages / home.tsx;
pages / detail.tsx;
styles / home.scss;
styles / detail.scss;
/ / instead
// The second way
pages / home / index.tsx;
pages / home / home.scss;
Copy the code
pages/
Do not use a folder under the React component. If you use a folder under the React component, the SCSS file will be reported during the build phase. So create a new one outsidestyles
Folder for SCSS files of each routing component)- Other folders such as
components
There are no errors, you can use the second method, the style and components in the same folder
4.1 the Link component
- Href: routing, as in
href="about"
, will renderpage/about.tsx
The content of the - As:
href
Rename it and then the browser address shows this URL;
The routing for href must be correct, requiring a file that actually exists in the page directory - Prefetch: prefetch, used by the current page
href/as
Displaying the browser URL as About1 below, the pages/about.tsx file is actually rendered, as is the actual route, if the server does not intercept the route otherwise
import Link from 'next/link';
<Link href="/about">
<a>About</a>
</Link>;
Copy the code
If the AS alias is set and the route is different from the original route, you need to configure another route on the server.
As follows:
- The client
// ...
return (
<div>
<Link href="/detail? id=123" as="/detail/123">
<a style={linkStyle}>Detail</a>
</Link>
</div>
);
// ...
Copy the code
- The service side
// server.ts
server.get('/detail/:id', (req: Req, res: http.ServerResponse) => {
app.render(req, res, '/detail', {
id: req.params.id,
});
});
Copy the code
prefetch
From the document
Some operations may require latency, but data can be prefetched using Prefetch
- Link component
<Link href="/about" prefetch={true}>
<a>About</a>
</Link>
Copy the code
- imperative
import { withRouter } from 'next/router';
function MyLink({ router }) {
return (
<div>
<a onClick={()= > setTimeout(() => router.push('/dynamic'), 100)}>
A route transition will happen after 100ms
</a>
{// but we can prefetch it!
router.prefetch('/dynamic')}
</div>
);
}
export default withRouter(MyLink);
Copy the code
push/replace
- object
import Router from 'next/router';
const handler = (a)= > {
Router.push({
pathname: '/about'.query: { name: 'Zeit'}}); };function ReadMore() {
return (
<div>
Click <span onClick={handler}>here</span> to read more
</div>
);
}
export default ReadMore;
Copy the code
4.2 Obtaining Routing Parameters for Non-Routing Components
React uses withRouter to get route parameters, but this is exported from next/ Router. Function components can also use useRouter
// src/components/header/index.tsx
import Link from 'next/link';
import Head from 'next/head';
import React from 'react';
import styles from './header.scss';
const Header = (a)= > {
return (
<div>
<Head>
<title>Next.js test</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
</Head>
<Link href="/">
<a className={styles.tag}>Home</a>
</Link>
<Link href="/about">
<a className={styles.tag}>About</a>
</Link>
<Link href="/detail? id=123" as="/detail/123">
<a className={styles.tag}>Detail</a>
</Link>
</div>
);
};
export default Header;
Copy the code
4.3 Route Translation
- will
href="/detail? id=123"
çš„ Query Indicates the URL of the queryconvertas="/detail/123"
çš„ Params type URL;
Href /as is static and generated dynamically if necessary<Link>
Can be
import Link from 'next/link';
<Link href="/detail? id=123" as="/detail/123">
<a className={styles.tag}>Detail</a>
</Link>;
Copy the code
- The matching URL of the server is
/detail/:id
Routing,
addParams parameters
And then render/detail
The correspondingpage/detail.tsx
File;
The refresh will result in 404 if route interception is not set on the server
// server.ts
// ...
function serverRun() {
const server = express();
/ / API interface
const controllers = require('./server/controller');
const apiRoute = ' '; // '/web';
server.use(apiRoute, controllers);
// Match the route with URL '/' and render the corresponding 'page/index.tsx' file
server.get('/'.(req: Req, res: http.ServerResponse) = > {
app.render(req, res, '/');
});
// Match the route with URL '/about' and render the corresponding 'page/about.tsx' file with '/about'
server.get('/about'.(req: Req, res: http.ServerResponse) = > {
app.render(req, res, '/about');
});
// Match the route with URL '/detail/:id', add parameter 'params', and render the' page/detail.tsx 'file corresponding to' /detail '
server.get('/detail/:id'.(req: Req, res: http.ServerResponse) = > {
app.render(req, res, '/detail', {
id: req.params.id,
});
});
server.get(The '*'.(req: http.IncomingMessage, res: http.ServerResponse) = > {
return handle(req, res);
});
server.listen(3000.(err: any) = > {
if (err) throw err;
console.log('> Ready on http://localhost:3000');
});
}
Copy the code
4.4 Routing Methods
Route intercepting router. beforePopState
In the browser, need component loading componentDidMount/useEffect execution, or complains
// src/pages/index.tsx
import Link from 'next/link';
import { /* Router, */ useRouter } from 'next/router';
import React, { useEffect } from 'react';
import Layout from '@/components/layout';
import styles from '@/styles/index.scss';
/** * props */
const Home = (a)= > {
const router = useRouter();
useEffect((a)= > {
// Route interception, which affects browser forward and back rendering results
// Router.beforePopState(({ url, as, options }: any) => {
// console.log('url: ', url);
// console.log('as: ', as);
// console.log('options: ', options);
// if (as === '/about') {
// console.log('about');
// return true;
/ /}
// return true;
// });
});
return (
<Layout>
<h1>{router.query.title}</h1>
<img
className={styles.img}
src="/static/images/4k-wallpaper-alps-cold-2283757.jpg"
/>
<div className={styles.content}>
<p>
This is our blog post. Yes. We can have a{' '}
<Link href="/link">
<a>link</a>
</Link>
. And we can have a title as well.
</p>
<h3>This is a title</h3>
<p>And here's the content.</p>
</div>
</Layout>
);
};
export default Home;
Copy the code
4.5 the Router events
Listen for internal events of the route
- RouteChangeStart (URL) – Triggered when the route starts to change
- RouteChangeComplete (URL) – Triggered after the route has changed
- RouteChangeError (err, url) – triggered when a routeChangeError occurs
- BeforeHistoryChange (URL) – Changes browser history before triggering
- HashChangeStart (URL) – Triggered when the hash changes
- HashChangeComplete (URL) – Triggered after the hash changes
Example:
import Router from 'next/router';
const handleRouteChange = (url) = > {
console.log('App is changing to: ', url);
};
Router.events.on('routeChangeStart', handleRouteChange);
Copy the code
Routing hop
// Select * from the about page where id = a11;
// To refresh the page, the id is asss, so try to keep both the same to avoid unnecessary problems
Router.push('/about? id=a11'.'/about/asss');
Copy the code
- Shallow Routing: indicates a Shallow route
Modifying the page URL without executing getInitialProps,
Router.push('/about? id=a11'.'/about/asss', { shallow: true });
Copy the code
5, App
The _app component is not destroyed unless manually refreshed
// src/pages/_app.tsx
import React from 'react';
import { NextComponentType } from "next";
import { Router } from 'next/router';
import App, { AppProps } from 'next/app';
interface Props {
Component: NextComponentType,
pageProps: AppProps,
router: Router
}
/** * App */
class myApp extends App<Props> {
public constructor(props: Props) {
super(props);
}
public componentDidUpdate() {
console.log('router: '.this.props.router);
}
public componentDidMount() {
console.log('router: '.this.props.router);
}
public render() {
const { Component, pageProps } = this.props;
return( <React.Fragment> <Component {... pageProps} /> </React.Fragment> ); } } export default myApp;Copy the code
6, components,
6.1 getInitialProps properties
Receives a method in which data can be retrieved and rendered on the server. Documents can only be used in components under Pages /
The refreshing of the current route is performed on the server. If the route is jumped from another route, the refreshing of the page is performed on the browser.
// src/pages/detail.tsx
import Head from 'next/head';
import { useRouter } from 'next/router';
import React from 'react';
import { inject, observer } from 'mobx-react';
import { homeStoreType } from '@/store/home';
import { Button, Row } from 'antd';
import Layout from '@/components/layout';
import styles from '@/styles/detail.scss';
function Detail(props: any) {
const router = useRouter();
const homeStore: homeStoreType = props.homeStore;
return (
<Layout>
<Head>
<title>Detail</title>
</Head>
<p className={styles.detail}>This is the detail page!</p>
id: {router.query.id}
<Row>count: {homeStore.count}</Row>
<Button onClick={()= > homeStore.setCount(homeStore.count + 1)}>
count++
</Button>
</Layout>
);
}
Detail.getInitialProps = async function(context: any) {
/** * If context.req is true and the server has req/res, print 'broswer' on the command line; * If another route jumps to the page without refreshing the page, context.req is false and printed on the browser console. * /
console.log('render-type: ', context.req ? 'server' : 'broswer');
return {
// data: 'detail'
};
};
const DetailWithMobx = inject('homeStore')(observer(Detail));
export default DetailWithMobx;
Copy the code
The received method takes one parameter context = {pathName, query, asPath, req, res, err} :
- Pathname: The fixed part of the URL pathname, as defined
/post/:id
, where pathname is/post
- Query: The object of the URL query parameter
- AsPath – Defines the route, for example
/post/:id
- req: HTTP request object (server only)
- res: HTTP response object (server only)
- Err: Error reported during rendering
6.2 dynamic import
Implement dynamic components using dynamic and import(); Dynamic The second argument is an object. The loading field is the loading before the loading is complete
// src/components/about.tsx import dynamic from 'next/dynamic'; import Head from 'next/head'; import React from 'react'; import Layout from '@/components/layout'; import styles from '@/styles/about.scss'; const Hello = dynamic(() => import('.. /components/hello-world/index'), { loading: () => <p>... </p>, }); function About() { return ( <Layout> <Head> <title>about</title> </Head> <p className={styles.about}>This is the about page</p> <Hello /> </Layout> ); } // About.getInitialProps = async function(context: any) { // return { // data: 'about' // }; // } export default About;Copy the code
7. Path alias
Configuring webpack directly with babel-plugin-module-alias is not effective
yarn add babel-plugin-module-alias -D
Copy the code
- Configuration. The babelrc
{
"plugins": [["module-alias", { "src": "./src"."expose": "@"}]],"presets": [
"next/babel"]},Copy the code
- tsconfig.json
{
"compilerOptions": {..."baseUrl": "src"."paths": {
"@ / *": [". / *"]}},... }Copy the code
8. Use SCSS
Official plugin: @zeit/next-sass
8.1 SASS
The installation
npm install --save @zeit/next-sass node-sass
Copy the code
or
yarn add @zeit/next-sass node-sass
Copy the code
configuration
When configured, use CSS modules just like in React
// next.config.js
const withSass = require('@zeit/next-sass');
module.exports = withSass({
cssModules: true.// The default is false, that is, globally valid
cssLoaderOptions: {
importLoaders: 1.localIdentName: '[local]___[hash:base64:5]',}});Copy the code
Or custom
// next.config.js
const withSass = require('@zeit/next-sass');
module.exports = withSass({
webpack(config, options) {
returnconfig; }});Copy the code
Using postcss
In the root directory of the project, create a new file postcss.config.js
// postcss.config.js
module.exports = {
plugins: {
autoprefixer: true,}};Copy the code
9, antd
Refer to this big guy’s article, mainly cssModules and ANTD on demand loading together with the use of other issues according to antD official website can be done, ANTD-Mobile as long as the corresponding ANTD to ANTD-mobile can be
.babelrc
{
"plugins": / / /"transform-decorators-legacy"["@babel/plugin-proposal-decorators", { "legacy": true }],
["module-alias", { "src": "./src"."expose": "@" }],
["import", { "libraryName": "antd"."style": "css"}]],"presets": [
"next/babel"]},Copy the code
next.config.js
The following is the common configuration, which will be incorporated into the configuration of next.config.js
// config/config.common.js
const path = require('path');
const cssLoaderGetLocalIdent = require('css-loader/lib/getLocalIdent.js');
// const isProd = process.env.NODE_ENV === 'production';
if (typeof require! = ='undefined') {
require.extensions['.css'] = (file) = > {};
}
/* Public configuration */
let configCommon = {
// assetPrefix: isProd ? 'https://cdn.mydomain.com' : '',
crossOrigin: 'anonymous'.cssModules: true.cssLoaderOptions: {
importLoaders: 1.localIdentName: '[local]___[hash:base64:5]'.getLocalIdent: (context, localIdentName, localName, options) = > {
const hz = context.resourcePath.replace(context.rootContext, ' ');
// Exclude styles under node_modules
if (/node_modules/.test(hz)) {
return localName;
}
returncssLoaderGetLocalIdent( context, localIdentName, localName, options ); }},distDir: 'next-build'.// Build the output directory, default '.next'
generateEtags: true.// Control cache etag, default true
pageExtensions: ['tsx'.'jsx'.'js'.'scss'].// the file suffix in the pages folder
webpack(config) {
if (config.externals) {
// Resolve the packing CSS error
const includes = [/antd/];
config.externals = config.externals.map((external) = > {
if (typeofexternal ! = ='function') return external;
return (ctx, req, cb) = > {
return includes.find((include) = >
req.startsWith('. ')? include.test(path.resolve(ctx, req)) : include.test(req) ) ? cb() : external(ctx, req, cb); }; }); }returnconfig; }};module.exports = configCommon;
Copy the code
State management MobX
Much like the React+Typescript single-page SPA project, except that the server rendering does not have Windows; So cache here first check whether the browser, then go to the browser API(sessionStorage);
_app.txs is actually rendered in the server, and the cache is restored in the browser. There is a time lag, and there is a warning (actually can be ignored, the server and the client cache does not need to synchronize, sessionStorage is also used because there is no need for a long cache. Of course, you can change it to localStorage as required
Single-page SPAs do not have this problem because they are rendered in the browser
const isBroswer: boolean = process.browser;
Copy the code
10.1 Project Entrance
// src/pages/_app.tsx
import { NextComponentType } from "next";
import { Router } from 'next/router';
import App, { AppProps } from 'next/app';
import React from 'react';
import { Provider } from 'mobx-react';
import store from '.. /store';
interface Props {
Component: NextComponentType,
pageProps: AppProps,
router: Router
}
/** * App */
class myApp extends App<Props> {
public constructor(props: Props) {
super(props);
}
public componentDidUpdate() {
console.log('router: '.this.props.router);
}
public componentDidMount() {
console.log('router: '.this.props.router);
}
public render() {
const { Component, pageProps } = this.props;
return( <React.Fragment> <Provider {... store}> <Component {... pageProps} /> </Provider> </React.Fragment> ); } } export default myApp;Copy the code
10.2 module
Listen to data using Autorun, will be executed once when the data changes; The module is then converted into A JS object using toJS
// src/store/home.ts
import * as mobx from 'mobx';
// Do not modify state directly outside of action
mobx.configure({ enforceActions: "observed"});
const { observable, action, computed, runInAction, autorun } = mobx;
const isBroswer: boolean = process.browser;
/** ** sessionStorage (' sessionStorage '); * However, there is a flash process, because '_app.txs' is actually rendered on the server, and the cache is restored in the browser, * there is a time lag, and there are warnings, depending on the need */
let cache = isBroswer && window.sessionStorage.getItem('homeStore');
// Initialize the data
let initialState = {
count: 0.data: {
time: '2019-11-20'}};// Cache data
if(isBroswer && cache) { initialState = { ... initialState, ... JSON.parse(cache) } }class Home {
@observable
public count = initialState.count;
@observable
public data = initialState.data;
@computed
public get getTime() {
return this.data.time;
}
@action
public setCount = (_count: number) = > {
this.count = _count;
}
@action
public setCountAsync = (_count: number) = > {
setTimeout((a)= > {
runInAction((a)= > {
this.count = _count; })},1000);
}
// public setCountFlow = flow(function *(_count: number) {
// yield setTimeout(() => {}, 1000);
// this.count = _count;
// })
}
const homeStore = new Home();
// Data is cached after data changes
autorun((a)= > {
const obj = mobx.toJS(homeStore);
isBroswer && window.sessionStorage.setItem('homeStore'.JSON.stringify(obj));
});
export type homeStoreType = typeof homeStore;
export default homeStore;
Copy the code
10.3 Module Management Output
// src/store/index.ts
import homeStore from './home';
/** * Use mobx state management */
export default {
homeStore,
};
Copy the code
10.4 Using Components
Here is the use of function components, the use of class components can be seen here
// src/pages/detail.tsx
import Head from 'next/head';
import { useRouter } from 'next/router';
import React from 'react';
import { inject, observer } from 'mobx-react';
import { homeStoreType } from '@/store/home';
import { Button, Row } from 'antd';
import Layout from '@/components/layout';
import styles from '@/styles/detail.scss';
function Detail(props: any) {
const router = useRouter();
const homeStore: homeStoreType = props.homeStore;
return (
<Layout>
<Head>
<title>Detail</title>
</Head>
<p className={styles.detail}>This is the detail page!</p>
id: {router.query.id}
<Row>count: {homeStore.count}</Row>
<Button onClick={()= > homeStore.setCount(homeStore.count + 1)}>
count++
</Button>
<Button onClick={()= > homeStore.setCountAsync(homeStore.count + 1)}>countAsync++</Button>
</Layout>
);
}
Detail.getInitialProps = async function(context: any) {
/** * If context.req is true and the server has req/res, print 'broswer' on the command line; * If another route jumps to the page without refreshing the page, context.req is false and printed on the browser console. * /
console.log('render-type: ', context.req ? 'server' : 'broswer');
return {
data: 'detail'}; };const DetailWithMobx = inject('homeStore')(observer(Detail));
export default DetailWithMobx;
Copy the code
11. Server
11.1 server. Ts
TSC server.ts generates server.js from TSC server.ts on the command line. In NPM script directly write ok; Don’t know how to automatically compile + restart the service
next(opts: object)
Opts have the following attributes:
- Dev (bool): indicates whether the development environment is developed-default false
- Dir (string): Next project location – default ‘.’
- Quiet (bool): Hides error messages containing server information – Default false
- Conf (object): Same as the object in next-config.js – default {}
const next = require('next');
constdev = process.env.NODE_ENV ! = ='production';
const app = next({
dev,
dir: '. '.quiet: false.conf: {},});Copy the code
Dynamic resource prefix assetPrefix
For example, if CDN is used locally or online, the resource is not the same as the server of the page
// server.ts
const express = require('express');
const next = require('next');
import * as http from 'http';
constdev = process.env.NODE_ENV ! = ='production';
const app = next({ dev });
const handle = app.getRequestHandler();
interface Req extendshttp.IncomingMessage { params? :any;
}
app
.prepare()
.then((a)= > {
serverRun();
})
.catch((ex: any) = > {
console.log(ex.stack);
process.exit(1);
});
function serverRun() {
const server = express();
/ / API interface
const controllers = require('./server/controller');
const apiRoute = ' '; // '/web';
server.use(apiRoute, controllers);
// Match the route with URL '/' and render the corresponding 'page/index.tsx' file
server.get('/'.(req: Req, res: http.ServerResponse) = > {
app.render(req, res, '/');
});
// Match the route with URL '/about' and render the corresponding 'page/about.tsx' file with '/about'
server.get('/about'.(req: Req, res: http.ServerResponse) = > {
app.render(req, res, '/about');
});
// Match the route with URL '/detail/:id', add parameter 'params', and render the' page/detail.tsx 'file corresponding to' /detail '
server.get('/detail/:id'.(req: Req, res: http.ServerResponse) = > {
app.render(req, res, '/detail', {
id: req.params.id,
});
});
server.get(The '*'.(req: http.IncomingMessage, res: http.ServerResponse) = > {
return handle(req, res);
});
server.listen(3000.(err: any) = > {
if (err) throw err;
console.log('> Ready on http://localhost:3000');
});
}
Copy the code
11.2 Writing an Interface
Use the default Express
It was supposed to be changed to KOA, but the page will be rendered, the server rendered page will be 404, the content will be rendered (in server-koa.ts)…
The module
// server/controllers/user.js
const Router = require('express').Router();
Router.get('/userInfo/:id', (req, res) => {
console.log('id: ', req.params.id);
res.send({
status: 200.data: {
name: 'Little brat'.sex: 'male'.age: '3',},message: ' '}); });module.exports = Router;
Copy the code
Module management
// server/controller.js
const Router = require('express').Router();
const user = require('./controllers/user');
Router.use('/user', user);
module.exports = Router;
Copy the code
Mount to the Server service
// server.ts
// ...
function serverRun() {
const server = express();
/ / API interface
const controllers = require('./server/controller');
const apiRoute = ' '; // '/web';
server.use(apiRoute, controllers);
// ...
}
Copy the code
Interface call
// src/pages/about.tsx
fetch('/user/userInfo/2')
.then((res) = > res.json())
.then((res) = > {
console.log('fetch: ', res);
});
Copy the code
Nginx is deployed locally, the request is proxied (proxy_pass) to next-test’s service (PM2 startup).
12, build,
npm script:
// package.json."scripts": {
"dev": "node server.js"."dev:tsc": "tsc server.ts"."build": "next build"."start": "cross-env NODE_ENV=production node server.js"},...Copy the code
Development environment:
yarn dev
Copy the code
Packaging:
yarn build
Copy the code
The resulting next-build folder (next-build is the configured output directory)
13, deployment,
Don’t know why, the project under the nginx new HTML folder (/ usr/local/etc/nginx/HTML/next – test) start the project and nginx, browser to access has been a 502 (single page SPA is normal)… /usr/local/website/next-test /usr/local/website/
13.1 pm2
With PM2, you can test locally, but ultimately deploy on the server
yarn global add pm2
Copy the code
The terminal goes into the project directory and then:
All commands
pm2 start yarn --name "next-test" -- run start
Copy the code
The script
Sh in the root directory of the project:
#deploy.sh
pm2 start yarn --name "next-test" -- run start
Copy the code
Terminal into the project directory:
. deploy.sh
Copy the code
Several PM2 commands:
- Pm2 show [id]: displays information about a PM2 application
- Pm2 List: Displays an overview of all PM2 applications
- Pm2 stop [id]/all: Stops an application. Multiple applications can be deleted, separated by Spaces, or stopped altogether
- Pm2 delete [id]/all: Deletes an application. Multiple applications can be deleted and separated by Spaces or all applications can be deleted
- Pm2 MONIT: monitors the status of pM2 started applications
- Pm2 restart: restart
- , etc.
13.2 Nginx
The PM2 service runs the program, and Nginx is responsible for enabling the HTTP service
Several nginx commands
- Nginx: start nginx
- Nginx -t: tests whether the nginx.conf configuration is correct
- Nginx -s stop: Stops the nginx
- Nginx -s reload: restarts the nginx
- , etc.
Configurations tested locally (MAC)
/usr/local/website
Nginx. Conf configuration:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
upstream next-test {
server 127.0.0.1:3000; # next-test Specifies the service port to start
}
# next-test
server {
listen 80;
server_name localhost; # Configure the domain name here
#charset koi8-r;
#access_log logs/host.access.log main;
error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location / {
proxy_pass http://127.0.0.1:3000; The request will be forwarded to the next-test node service
proxy_redirect off;
# root html;
indexindex.html index.htm; }}# movie-DB: single page SPA
server {
listen 81;
server_name localhost; # Configure the domain name here
root /usr/local/website/movie-db/;
location / {
try_files $uri $uri/ @router;
}
location @router {
rewrite ^.*$/index.html last;
}
# error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
roothtml; }}# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:! aNULL:! MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
#}
#}
include servers/*;
}
Copy the code
The next thing I need to do
The database
MySQL/MongoDB
GrahpQL
As if called API query language, the main interface aggregation of a thing it; It is for the aggregation of the back-end microservice interface, and then the front-end page as long as the request through the aggregation of the interface, there is no need to repeatedly request the back-end microservice small interface; I don’t know if I got it right
Some of the problems
-
From a level 1 route to a level 2 route and then refresh, browser back, THE URL changes but the content stays the same! This is a bug, issue #9378, fixed
-
Styles.chunk. CSS is not associated with CSS, but SCSS + CSS modules have been converted.
-
Next. Js seems to have a problem with koA, the server rendered the page to look at the web request there will be 404, but the page rendered; Or dynamic route (/detail/:id) 404… Node.js services built using KOA alone do not have this problem (here)
reference
- Documents to nextjs.org
- And some of the big names on the Internet