React CRA를 이용하지 않고 프로젝트 생성(1)에 이어서 추가로 Typescript를 사용 할 수 있게 구성해 보겠습니다.
타입스크립 관련 모듈을 설치 합니다.
// 타입스크립트를 사용하기 위한 기본 모듈
npm i -g typescript
or
npm i -D typescript
npm i -D @types/react @types/react-dom //리액트에서 사용할 타입 모듈
npm i -D ts-loader // 웹팩에서 타입스크립트 사용하기 위한 모듈
ts-loader는 tsconfig.json파일은 참고해서 동작하므로
tsconfig.json파일은 생성해 줍니다.
기본 tsconfig.json 생성
tsc --init // 글로벌 설치시
or
npx tsc --init // 로컬 설치시
tsconfig 환경을 아래와 같이 설정해준다.
{ "compilerOptions": { "target": "es6", // 자바스크립트 버전 es6=es2015와 같고 현재 es2021까지 지원합니다. "module": "commonjs", // 어떤모듈로 생성할지 지정 "rootDir": "./src", // 소스파일 위치 "outDir": "./dist", // 배포파일 생성 위치 "jsx": "react", // jsx 컴파일 방법 지정 (preserve, react, react-native) "moduleResolution": "node", // 모듈 해성방법 지정 (classic, node) "esModuleInterop": true, // es6와 commonjs간 모듈 호환성을 위해 true로 설정한다. "forceConsistentCasingInFileNames": true, // 대소문자를 정확히 구별할지 강제 "strict": true, // 타입 체킹 동작 활성 "skipLibCheck": true, // 모든 선언 파일 (.d.ts)의 타입 체킹을 스킵하도록 설정 "sourceMap": true, // map파일 생성 여부 "noImplicitAny": true, // <any> 타입을 허가하지 않음 }, "exclude": ["node_modules"], "typeRoots": ["node_modules/@types"], //타입 스크립트가 정의되 있는 type을 찾는 위치 include 위치에 있는 .d.ts 파일은 자동으로 인식되므로 추가할 필요 없음 "include": ["src/**/*"] // 티입 추가 위치 }
기존 webpack.config.js 파일을 아래와 같이 수정한다.
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 번들 파일 생성 위치
const bundlePath = path.resolve(__dirname, 'dist/');
const jsxRegex = /\.(js|jsx)$/; // js, jsx regex
const tsxRegex = /\.(ts|tsx)$/; // ts, tsx regex
// /\.ts(x?)$/,
module.exports = (_env, argv) => {
let entryPoints = {
main: {
path: './src/index.tsx',
outputHtml: 'main.html',
build: true
},
config: {
path: './src/config.tsx',
outputHtml: 'config.html',
build: false
}
};
let entry = {};
// 웹팩 플러그인 추가 구성
let plugins = [new webpack.HotModuleReplacementPlugin()];
Object.entries(entryPoints).map(([key, value]) => {
if (value.build) {
entry[key] = value.path;
if (argv.mode === 'production') {
plugins.push(
new HtmlWebpackPlugin({
inject: true,
chunks: [key],
template: './public/template.html',
filename: value.outputHtml
})
);
}
}
return null;
});
let config = {
entry,
optimization: {
minimize: true // 불필요한 코드 최적화
},
devtool: 'source-map', // Webpack의 출력물에서 디버깅을 하기위해 소스 맵을 허용합니다.
module: {
rules: [
{
test: tsxRegex,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'ts-loader'
}
]
},
{
// test: /\.(js|jsx)$/,
test: jsxRegex,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react'
],
plugins: []
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: 'file-loader',
options: {
name: 'img/[name].[ext]'
}
},
// 모든 '.js' 출력 파일은 'source-map-loader'에서 다시 처리한 소스 맵이 있습니다.
{
enforce: 'pre',
test: /\.js$/,
loader: 'source-map-loader'
}
]
},
resolve: { extensions: ['*', '.js', '.jsx', '.ts', '.tsx'] },
output: {
filename: '[name].js',
path: bundlePath
},
plugins
};
if (argv.mode === 'development') {
config.devServer = {
static: './public',
host: 'localhost',
// host: '192.168.0.242',
// host: '0.0.0.0',
port: 3008,
historyApiFallback: {
index: 'index.html'
},
hot: true
// allowedHosts: ['com.arenacast.io'],
};
config.performance = {
hints: false,
maxEntrypointSize: 512000,
maxAssetSize: 512000
};
config.output = {
// publicPath: "/",
path: path.resolve(__dirname, './dist'),
filename: '[name].js'
};
}
return config;
};
rules에 ts-loader 추가
resolve - extensions 에 .ts, .tsx 확장자 추가
타입스크립트로 index 모듈을 작성 한다.
index.tsx
import * as React from 'react';
// import * as ReactDOM from 'react-dom';
import * as ReactDom from 'react-dom/client';
import { Hello } from './components/hello';
const container = document.getElementById('example');
if (!container) throw new Error('Failed to find the root element'); // react18 에서 typescript지원부분 오류로 인한 에러 type업데이트 될때 까지 해당 코드를 사용한다.
// react18에서는 render가 createRoot로 변경
ReactDom.createRoot(container).render(
<React.StrictMode>
<Hello compiler="TypeScript" framework="React" />
</React.StrictMode>
);
react18로 업데이트 되면서
몇가지 변경점이 생겼다
react-dom > react-dom/client로 변경
ReactDom.render > ReactDom.createRoot(container).render 로 변경
// react18 에서 typescript지원부분 오류로 인한 에러 type업데이트 될때 까지 해당 코드를 사용한다.
if (!container) throw new Error('Failed to find the root element');
실행해보자
npm run start
by Kazel