본문 바로가기

React.JS

React.js와 Codeigniter 연결하기

얼마 전 회사의 새로운 프로젝트에서 코드이그니이터와 리엑트를 연결하는 경험을 하였다. 코드이그나이터는 php로 작성된 웹 프레임워크이며, 언어와 프레임웍 모두 비교적 레거시라고 평가받고 있다. 반면 리엑트는 비교적 새로운 프론트 프레임워크인 상황이었다. 이 상황에서 둘 사이의 연결을 설명해놓은 자료를 찾기는 쉽지 않았다. 레거시에 새로운 프레임 웍을 연결하는 작업은 개발팀이 더 효율적으로 개발을 할 수 있는 첫 시발점을 만드는 것이었기에 흥미가 많이 갔던 작업이었다. 코드이그나이터에 리엑트를 도입해보고자 하는 누군가에게 도움이 되고자 경험을 공유해본다.

코드이그나이터와 리엑트 라우터 연결 구성

코드이그나이터는 서버사이드 렌더링을 하며, 폴더 경로가 라우터가 되는 특징이 있다. 하지만 index.html 하나로 모든 것을 표현하는 SPA특성상 브라우저에 URL을 입력하면 index.html로만 연결을 시킨다. 리엑트에서는 이를 해결하기 위해 react-router-dom라이브러리를 제공하며 url에 따라 컴포넌트를 렌더링 해주는 기능을 제공한다. 이를 코드이그나이터와 다음과 같이 연결시켰다.

1) webpack.dev.js에서 historyApiFallback: true로 하였다. → 설정해 놓은 url이외의 경로로 접근했을 때  index.html을 제공할지를 결정하는 옵션이다.

2) routes.php에서 /adm(:any)경로로 끝나는 경우에 웹팩에서 빌드된 index.html로 연결시켰다.

이렇게 하면 사용자가 url을 직접 입력해서 들어오더라도 index.html안에 설정된 리엑트 라우터 경로에 따라 컴포넌트가 렌더링 되고, 사용자가 느끼기에 실제로 서버가 렌더링 해준 효과를 가지게 된다.

코드이그나이터와  axios 비동기 통신 주의사항

php에서는 기본적으로 json 데이터를 받을 수 없고 form 데이터를 받을 수 있다. 하지만 axios에서는 기본적으로 javascript object를 json형태로 보내기 때문에 이를 해결해줘야 한다. qs 라이브러리(https://www.npmjs.com/package/qs)를 사용하여 이를 해결할 수 있다. 

웹팩 환경설정

웹팩 환경설정은 코드이그나이터와 연결한다고 해서 특별히 다른 점은 없었다. 다만 번들링 된 파일을 코드이그나이터에서 제공해줄 수 있는 위치로만 연결시켜주는 것에 주의하자. 웹팩 설정은 일일이 다 기억할 수 없기에 다른 블로그나 공식 문서를 많이 참조하여 진행하였다.

관련하여 찾아보니 설정파일 하나에 dev와 prod를 분기 처리하는 방법이 있었고 각각의 파일을 따로 만들어서 merge 하여 사용하는 방법이 있었는데 후자를 선택하였다. 각각의 파일이 자신이 가진 스코프를 더 명확하게 하기 위해서였으며 웹팩팀에서도 각각의 파일로 나누는 것을 권장하기 때문이다.

다음과 같이 총 3개의 파일로 웹팰 설정을 나누고 webpack merge 하여 사용하였다.

 

webpack.common.js

dev환경과 prod환경에서 공통으로 쓰이는 설정은 이 파일에 담아준다.

const HtmlWebpackPlugin = require('html-webpack-plugin');
const AntdDayjsWebpackPlugin = require('antd-dayjs-webpack-plugin');

module.exports = {
    entry: "./src/index.js",
    module: {
        rules: [
            {
                test: /\.html$/,
                use: [
                    {
                        loader: 'html-loader',
                        options: {
                            minimize: true,
                        },
                    },
                ],
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
        ]
    },
    resolve: {
        modules: ['node_modules'],
        extensions: ['.js', '.json', '.jsx', '.css'],
    },
    plugins: [
        new HtmlWebpackPlugin({
            // <script />가 추가된 html 파일이 복사. ./src/index.html 파일이 ./dist/index.html로 복사
            template: 'public/index.html',
            filename: './index.html',
            showErrors: true
        }),
        new AntdDayjsWebpackPlugin()
    ],
}

 

webpack.dev.js

개발 환경에서는 웹팩 데브 서버를 활용할 것이다. 웹팩 데브 서버를 실행시키면 localhost가 origin이 되고 서버에서는 localhost에서 보내는 요청을 허용해 놓지 않았기에 cors 관련된 에러가 날것이다. 이를 피하기 위해 proxy 설정을 해줘야 한다. proxy 설정을 통해서 서버에 localhost에서 보내는 요청이 아니라 서버에서 허용해 놓은 도메인으로 바꿔서 요청을 보낼 수 있게 된다. 이번 프로젝트의 경우 요청 경로가 /ajax/ 로 시작할 때에만 proxy설정을 적용하였다.

const { merge } = require("webpack-merge");
const webpack = require('webpack');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const common = require('./webpack.common');
const port = process.env.PORT || 3000;

module.exports = merge(common,{
    mode: 'development',
    devtool: 'inline-source-map', // 트랜스파일 된 코드를 원래 소스코드로 맵핑하여 에러가 발생했을 때 정확한 파일명을 알려줌 (개발시에만 사용)
    // 개발 서버 설정
    output: {
        publicPath: '/'
    },
    module: {
        rules: [
            {
                test: /\.[jt]sx?$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: require.resolve('babel-loader'),
                        options: {
                            plugins: [
                                require.resolve('react-refresh/babel'),
                            ].filter(Boolean),
                        },
                    },
                ],
            },
        ],
    },
    plugins: [new webpack.HotModuleReplacementPlugin(), new ReactRefreshWebpackPlugin()],
    devServer: {
        historyApiFallback: true, // 설정해놓은 url 이외의 url 경로로 접근했을때 index.html을 서빙할지 결정
        port: port,
        open: true, // open page when start
        proxy: {
            '/ajax/*': {
                target: 'http://dev-fs.conects.com',
                changeOrigin: true
            }
        }
    },
});

 

webpack.prod.js

배포환경에서는 번들링 된 하나의 파일을 코드이그나이터의 skin 폴더에 위치시키도록 설정해주면 된다.

const { merge } = require("webpack-merge");
const path = require("path");
const common = require("./webpack.common");

module.exports = merge(common,{
    mode: "production",
    module:{
        rules: [{
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            use: {
                loader: 'babel-loader',
            },
        },]
    },
    output: {
        filename: '[name].bundle.js',
        path: path.join(__dirname, '../../skin/fs/dist/'),
        publicPath: '/skin/fs/dist/'
    },
    devtool: "cheap-module-source-map",
    optimization: {
        minimize: true,
    },
});

 

실행 방법

환경설정을 다 했으면 실행이 잘 되는지 확인해 보자. 

1) 노드 모듈 설치

  • 위치: /프로젝트명/public_html/js/webpack-react 
  • 명령어: npm install (npm i 로 줄여서 가능)
    • package.json에 적혀 있는 모듈들이 설치된다.

 

2) 빌드 방법

기본적으로 package.json파일의 scripts가 실행 명령어의 모음이며, 프로젝트에서는 아래 명령어로 동작하게 설정해 놓았다. 

  • 위치: /프로젝트명/public_html/js/webpack-react 
  • dev모드 일 경우 : npm run dev
    • 메모리 상의 웹팩 데브 서버에서 작동 (실시간 변경사항 브라우저 반영)
  • prod모드 일 경우: npm run build
  • watch모드 : npm run watch  

 

3) 빌드된 결과물의 위치 

  • skin/dist/

웹팩을 통해 번들링 된 파일이 웹팩의 output에 지정된 경로에 생성되는 것을 확인할 수 있다.