Gilvert 2018. 10. 29. 16:50
728x90

Hoc를 사용하여 코드 스플리팅



코드 스플리틍: 컴포넌트편


1. state에 기본값

2. 클릭했을때 호출: setState

3. 컴포넌트가 존재하면 보이기


1. state에 null 기본값

2. 클릭했을때 state에 set

3. 컴포넌트가 존재하면 보여주기: SpliteMe && <SpliteMe/>


매번 state에 담기가 귀찮으니까

Hoc을 사용 훅훅훅훅


Higher order component



주로 with~~~ 라고 지음

withRequest


기본원리

1. 파라미터로 컴포넌트를 받아오고

2. 함수 내부에서 새로운 컴포넌트를 만든 다음

3. 해당 컴포넌트 안에서 파라미터로 받아온 컴포넌트를 랜더링하는 것




코드스플리팅 함수 사용


해당 컴포넌트를 가지고 온다.

state 기본값 null 작성

가지고 온 컴포넌트가 있으면 setState

있으면 최종 랜더



라우팅


<Link to="/">Home</Link>


<Route exact path="/" component={Home} />


링크를 누르는 것과

해당 페이지를 불러오는 것은 별개이다.




reactDom Server. renderToString

- 동기적으로 작동


- 개인화 된 데이터는 서버 사이드 랜더링을 피한다.


prerender


- 검색엔진 최적화: 크롤러 일 경우에만 대신 랜더링해줘서 반환




koa 사용


정적 파일 제공

statc

- ja , css 파일을 서버에서 제공



koa-static 불러오고 -> 미들웨어



app.use(serve(path.resolve(__dirname, '../build/')));

app.use(ctx => {

  ctx.body = 'Hello World';

});


클라이언트에서는 빌드를 해놓은 상태임



서비스 워커 때문에

서버에서 없어도 캐시 영향으로 페이지가 나옴

index.html



서버 측에서 준비되지 않은 요청이 들어왔을시

리액트 어플리케이션이  띄어져 있는 index.htm의 내용을 보여주어야 함


캐시를 비워도 사용 가능하게끔



노드는 jsx를 불러올수 없음

그래서 babel를 사용해야함



웹팩을 이용하여 리액트 관련 코드만 미리 빌드해서 사용하기



index.js에서 

id가 root인 DOM을 찾아서 랜더링


서버를 위한 엔트리 파일




import React from 'react';

import ReactDOMServer from 'react-dom/server';

import { StaticRouter } from 'react-router';

import App from 'shared/App';


const render = (location) => ReactDOMServer.renderToString(

    <StaticRouter location={location}>

        <App/>

    </StaticRouter>

);


export default render;



이것을 웹팩으로 번들링 해주면 된다.




config 파일

===================================================================


use strict';


const path = require('path');

const webpack = require('webpack');

const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');

const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');

const getClientEnvironment = require('./env');

const paths = require('./paths');



const publicUrl = '';

const env = getClientEnvironment(publicUrl);


module.exports = {

  entry: paths.serverRenderJs,

  // Node.js 내장 모듈과 충돌이 일어나지 않으며 require 로 불러올 수 있는 형태로 번들링합니다

  target: 'node',

  output: {

    // 정해준 서버 경로에 render.js 라는 파일명으로 저장합니다

    path: paths.server,

    filename: 'render.js',

    libraryTarget: 'commonjs2' // node 에서 불러올 수 있도록, commonjs2 스타일로 번들링 합니다

  },

  resolve: {

    modules: ['node_modules', paths.appNodeModules].concat(

      process.env.NODE_PATH.split(path.delimiter).filter(Boolean)

    ),

    extensions: ['.js', '.json', '.jsx'],

  },

  module: {

    strictExportPresence: true,

    rules: [

        // 자바스크립트 이외의 파일들을 무시합니다.

        {

            exclude: [

                /\.(js|jsx)$/,

                /\.json$/

            ],

            loader: 'ignore',

        },

      // 자바스크립트는 Babel 을 통하여 트랜스파일링합니다

      {

        test: /\.(js|jsx)$/,

        include: paths.appSrc,

        loader: require.resolve('babel-loader'),

        options: {

          cacheDirectory: true,

        },

      }

    ],

  },

  plugins: [

    // 필수 플러그인만 넣어줍니다

    new webpack.DefinePlugin(env.stringified),

    new CaseSensitivePathsPlugin(),

    new WatchMissingNodeModulesPlugin(paths.appNodeModules),

  ]

};





-------------------------------------------------------------------------------





'use strict';


process.env.BABEL_ENV = 'production';

process.env.NODE_ENV = 'production';


/* 나중에 클라이언트쪽 코드에서 process.env.APP_ENV 값을 통하여 

서버일때만, 혹은 브라우저일때만 특정한 작업을 하도록 설정 할 수 있습니다. */

process.env.APP_ENV = 'server'; 



process.on('unhandledRejection', err => {

  throw err;

});



require('../config/env');


const webpack = require('webpack');

const config = require('../config/webpack.config.server'); // 서버용 환경설정을 지정

const paths = require('../config/paths');

const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');

const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');


if (!checkRequiredFiles([paths.serverRenderJs])) {

  process.exit(1);

}


function build() {

  console.log('Creating an server production build...');


  let compiler = webpack(config);

  return new Promise((resolve, reject) => {

    compiler.run((err, stats) => {

      if (err) {

        return reject(err);

      }

      const messages = formatWebpackMessages(stats.toJson({}, true));

      if (messages.errors.length) {

        return reject(new Error(messages.errors.join('\n\n')));

      }

      return resolve({

        stats,

        warnings: messages.warnings,

      });

    });

  });

}


build();






const fs = require('fs');

const path = require('path');

const render = require('./render').default; // ES6 형식으로 만들어진 모듈이므로, 뒤에 .default 를 붙여주어야합니다.


// html 내용을 해당 상수에 저장합니다

const template = fs.readFileSync(path.join(__dirname, '../../build/index.html'), { encoding: 'utf8'});


module.exports = (ctx) => {

    // 요청이 들어올 때 현재 경로를 render 함수에 전달시켜서 문자열을 생성합니다

    const location = ctx.path;

    const rendered = render(location);

    // 해당 문자열을, 템플릿에 있는 '<div id="root"></div> 사이에 넣어줍니다.

    const page = template.replace('<div id="root"></div>', `<div id="root">${rendered}</div>`);


    // 렌더링된 페이지를 반환합니다.

    ctx.body = page;

}










가우넷 구름 USB 충전식 양면 대용량 보조배터리 손난로, 단일 상품, 화이트



"파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음"