SSR 템플릿 어플리케이션 - 소비자 가격 인하
요약
이것은 블로그 웹 페이지에 사용되는 템플릿 프로그램입니다.Webpack 4에서 서버측 렌더링을 사용하고 게시물 페이지를 태그 파일로 채웁니다.
안녕하세요!
템플릿 블로그 응용 프로그램 라이브러리를 공유하고 싶습니다.사용자가 웹 페이지를 요청할 때, 이 프로그램은 서버에서 렌더링을 합니다.서버 쪽 렌더링인 거 다 알아요.그것은 두 가지 예를 포함한다. 하나는 정적 웹 페이지(html만 있음)로 돌아가고, 다른 하나는 JS 파일을 포함하여 웹 페이지를 더욱 동적으로 만든다.이 JS 파일은 Webpack과 Babel에서 포장하고 전송합니다.Redux가 설정되어 있기 때문에 프로그램에 더 많은 기능을 추가하지 않도록 상호작용을 할 수 있습니다.마지막으로, 이것은 HTML 파일로 표시할 수 있는 태그 파일을 사용하는 방법을 보여 주는 블로그 프로그램입니다.
개인적으로는 개인 창을 사용하고 브라우저의 캐시를 조심하는 것이 좋습니다
개술
두 방안의 초기 절차
정적 파일 생성
SSR은 어떻게 웹 패키지를 사용합니까?
이 과정을 보여 주세요.
따라서script 명령은 먼저 웹팩을 사용하여transfile과bundle 프로세스를 진행한 다음에 노드를 실행합니다.js 서버.
"scripts": {
"start": "webpack --mode production && node index.js",
"dev": "webpack --mode production && nodemon index.js",
"build": "webpack --mode production"
},
웹 패키지 구성
Webpack의 출력은 JS 파일이며 마지막 HTML 파일의 태그 스크립트에서 호출됩니다(완전히 정적 파일이 아닐 경우).서버는 HTML과 상호 작용할 수 있도록 파일을 정적 파일로 사용해야 합니다.
패키지 구성 파일은 다음과 같습니다.
// webpack.config.js
const path = require('path');
module.exports = {
entry: {
client: './src/ssr/reactiveRender/client.js',
},
output: {
path: path.resolve(__dirname, 'assets'),
filename: '[name].js',
},
module: {
rules: [{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' }],
},
};
엔트리 파일은 일반 React 렌더링 파일과 같지만 두 가지 차이가 있습니다.import React from 'react';
import { hydrate } from 'react-dom';
import { Provider } from 'react-redux';
import configureStore from '../../redux/configureStore';
import Home from '../../sections/Home';
const state = window.__STATE__;
delete window.__STATE__;
const store = configureStore(state);
hydrate(
<Provider store={store}>
{' '}
<Home />{' '}
</Provider>,
document.querySelector('#app')
);
사용window.__STATE__
단계는 서버에서 Redux 저장소를 생성하여 클라이언트가 사용할 JS에 전달하는 것입니다.그리고 우리는
hydrate()
로 대체한다render()
.둘은 기본적으로 같지만 hydrate()
ReactDomServer를 렌더링하는 원소수합에 사용됩니다.그것은 서버와 클라이언트의 내용이 같음을 확보한다.노드js 서버
대부분의 경우, 우리는express를 사용하여 일을 더욱 간단하게 한다.우리의 인덱스 파일은 일반express 설정 + 바베타 레지스터를 가져옵니다.
Babel/register는 테스트 환경에 사용됩니다.바벨을 노드에 등록해서 실행할 때 사용합니다.require 갈고리는 노드에 연결된 Require를 동적으로 자동으로 컴파일합니다.
이것은 웹 패키지 of rollup 같은 구축 절차가 필요 없고, 바벨을 실행해야 할 때 완성된 것입니다.
그래서 색인에 가져옵니다.js 파일은 이 코드가 노드를 실행하기 때문에 ES6 문법을 사용하는 데 도움을 줄 것입니다.js 서버는 웹 패키지를 통과하지 않습니다.
우리는 페이지를 보여 주는 경로를 설정했다.이 작업은
"/"
를 사용하여 수행합니다.// mw function to start SSR
// render page with list of posts
//
app.get('/', async (req, res) => {
// render our HTML file
const finalHtml = await ssrV2({
content: listPages.pageTitles,
Component: Home,
});
res.setHeader('Cache-Control', 'assets, max-age=604800');
res.send(finalHtml);
});
나는 반응 페이지를 위해 다른 경로를 만들었다.app.get('/reactive_page', (req, res) => {
// render Home Reactive component
// include js file which also contains Redux
const finalHTML = ssrReactive(listPages);
res.send(finalHTML);
});
SSR 모듈
이곳의 관건은
renderToString
이다.React 애플리케이션을 받아서 서버에 표시합니다.이제 우리는 HTML 내용이 생겨서 최종 HTML에 주입될 것이다.이렇게 하면 React 구성 요소를 정적 표식으로 표시할 수 있습니다.Render a React element to its initial HTML. React will return an HTML string. You can use this method to generate HTML on the server and send the markup down on the initial request for faster page loads and to allow search engines to crawl your pages for SEO purposes.
If you call ReactDOM.hydrate() on a node that already has this server-rendered markup, React will preserve it and only attach event handlers, allowing you to have a very performant first-load experience.
// ssr module
import React from 'react';
import { renderToString } from 'react-dom/server';
import remark from 'remark';
import html from 'remark-html';
import template from './template';
// render a component and inserts content to it
// returns an HTML file
const ssr = async ({ content = '', Component, htmlContent = '' } = {}) => {
// convert the mk content into html syntax
const contentHtml = await remark().use(html).process(htmlContent);
let appContent = renderToString(
<Component content={content} htmlContent={contentHtml} />
);
// create a full HTML file with app content
const fullHtml = template('Post', appContent);
return fullHtml;
};
export default ssr;
또한 스토리지 컨텐트를 사용하여 구성 요소를 렌더링할 수도 있습니다.Redux 스토리지를 생성하여 공급업체의 고급 구성 요소에 전달했습니다.
마지막으로, 우리는 현재의 상점 상태를 저장합니다.
import React from 'react';
import { renderToString } from 'react-dom/server';
import { Provider } from 'react-redux';
import configureStore from '../../redux/configureStore';
import template from './template';
import HomeReactive from '../../sections/HomeReactive';
/*
creates the preloaded state from the Redux store
renders the content that will be injected to the html file
in the server side, to be sent to the client
*/
const srr = initialState => {
// init our redux store
const store = configureStore(initialState);
// render our app content and returns a HTML string
let appContent = renderToString(
<Provider store={store}>
<HomeReactive />
</Provider>
);
const preloadedState = store.getState();
const finalHtml = template('reactive app', preloadedState, appContent);
return finalHtml;
};
export default srr;
템플릿 모듈
이 모듈은 HTML 파일의 나머지 내용을 설정합니다.그리고 윈도우 대상에 레드ux 저장소를 설정합니다.너는 곧 우리가 어디에서 그것을 소비할지 보게 될 것이다.
반환된 이 HTML 파일은 우리의 노드입니다.js 서버가 정적 파일로 되돌아옵니다.
스크립트를 추가할 필요가 없으면, 스크립트를 삭제하고 완전한 정적 파일을 보낼 수 있습니다.
// html skeleton provider
export default function template(title, initialState = {}, content = '') {
let scripts = ''; // Dynamically ship scripts based on render type
if (content) {
scripts = ` <script>
window.__STATE__ = ${JSON.stringify(initialState)}
</script>
<script src="assets/client.js"></script>
`;
}
let page = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title> ${title} </title>
<link rel="stylesheet" href="assets/style.css">
</head>
<body>
<div class="content">
<div id="app" class="wrap-inner">
${content}
</div>
</div>
${scripts}
</body>
`;
return page;
}
무엇이 가격 인하 문건입니까?
Markdown is a lightweight markup language that you can use to add formatting elements to plaintext text documents.
다음 단계는 이러한 가격 인하 파일을 사용하는 과정입니다.
게시물 목록 가져오기(가격 인하 파일)
이것은 내용 디렉터리를 읽고 파일에서 모든 이름을 가져오는 모듈입니다.
export default function getAllPages() {
const pagesLayers = {};
// separate directories from files in the content directory (initial)
const dividedElements = readFilesProcess(process.cwd(), 'content');
// save the root pages
pagesLayers['root'] = dividedElements.pages;
// start reading deeper directories
dividedElements.directories.forEach(directory => {
readProcess(directory, path.join(process.cwd(), 'content'));
});
// this function is a clousure, because we need to access pagesLayers
//to keep tracking the result
function readProcess(directory, directoryPath) {
// separate directories from files
const dividedElLayer = readFilesProcess(directoryPath, directory);
// save pages from current directory
pagesLayers[directory] = dividedElLayer.pages;
// check if there are more directories to check in the current layer
if (dividedElLayer.directories.length !== 0) {
// pass the current layer path to could keep going deeper
dividedElLayer.directories.forEach(directory => {
readProcess(directory, layerPath);
});
}
}
return pagesLayers;
}
변수 페이지Layers는 파일 이름을 저장합니다.컨텐트 디렉토리에는 페이지 레이어에 등록 정보로 저장된 디렉토리를 포함할 수 있습니다.이 과정은 주로 디렉터리에 있는 파일을 읽고 이를 페이지 (md 파일) 와 하위 디렉터리로 나누어 페이지 Layers 변수에 저장하고 하위 디렉터리를 반복하는 것을 포함한다.
readFilesProcess 함수는 경로 및 대상 디렉토리를 수신합니다.대상 디렉토리에서 파일을 읽습니다.마지막으로, 태그 파일을 디렉터리에서 분리합니다.
// read the elements from target directory
function readFilesProcess(startPath, targetDirectory) {
// get full path of the directory
const layerPath = path.join(startPath, targetDirectory);
// read all files
const layerFiles = fs.readdirSync(layerPath);
const accumulator = {
pageTitles: [],
fullPages: {},
directories: [],
};
// separate the files in pages and directories
return layerFiles.reduce((accumulator, currentVal) => {
// avoid adding next.js files that are not pages
if (currentVal.endsWith('.md')) {
// read the file
const fileContent = fs.readFileSync(layerPath + `/${currentVal}`, 'utf8');
const newPage = {
title: currentVal,
content: fileContent,
//content: 'content',
};
accumulator.fullPages[currentVal] = newPage;
accumulator.pageTitles.push(currentVal);
} else {
accumulator.directories.push(currentVal);
}
return accumulator;
}, accumulator);
}
나는 당신이 .md
이외의 다른 파일을 추가하지 않는다고 가정하지만, 추가하면 알고리즘을 바꾸기만 하면 된다.반환된 객체의 구조 예는 다음과 같습니다.
{
pageTitles: [ 'Minimum_Spanning_Tree.md', 'crud_app.md', 'set_up_prisma.md' ],
fullPages: {
'Minimum_Spanning_Tree.md': { title: 'Minimum_Spanning_Tree.md', content: 'content' },
'crud_app.md': { title: 'crud_app.md', content: 'content' },
'set_up_prisma.md': { title: 'set_up_prisma.md', content: 'content' }
}
}
페이지타이틀 속성은 모든 게시물의 메뉴를 표시하는 데 사용됩니다.fullPages 속성은 게시물 페이지의 내용을 포함합니다.
Reference
이 문제에 관하여(SSR 템플릿 어플리케이션 - 소비자 가격 인하), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/georgexx009/ssr-bolerplate-app-consumes-markdowns-47hi텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)