2024. 3. 9. 15:30

비주얼 스튜디오 버전별로 프론트엔드 프로젝트 구성이 조금씩 다릅니다.

이 포스팅은 비주얼 스튜디오 커뮤니티 2022(버전 17.8.3) 기준입니다.

 

이 버전에서는 '.esproj(자바스크립트 프로젝트 시스템)'로 프론트엔드 프로젝트를 구성하는 것이 권장 사항입니다.

이 포스팅에서는 타임스크립트가 포함된 프로젝트를 예제로 사용하고 있습니다.

이 포스팅에서는 편의상 웹팩(webpack)를 사용했지만, 구성은 마음대로 해도 됩니다.

 

 

1. 프로젝트 생성 

새 프로젝트 추가 > Blank TypeScript Project

를 선택합니다.

 

타입스크립트를 사용하지 않으려면 'Blank JavaScript Project'를 선택합니다.

수동으로 타입스크립트를 구성할 생각이어도 'Blank JavaScript Project'를 선택합니다.

 

 

프로젝트 생성이 끝나고 솔루션 탐색기를 확인하면 아래와 같이 구성되어 있습니다.

 

프로젝트가 생성되면 노드(node) 프로젝트 구성이 됩니다.

노드(node) 프로젝트에 대한 지식이 있다면 여기서부터는 이 포스팅과 상관없이 구성하셔도 됩니다.

 

 

2. 구성 변경 

모든 소스 파일은 'src'폴더에서 관리할 예정이므로 아래 파일은 제거해 줍니다.

- app.js

- app.js.map

- app.ts

 

 

2-1. 테스트 브라우저 설정하기 

.vscode > launch.json

을 열어 아래와 같이 수정합니다.

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "edge",
      "request": "launch",
      "name": "localhost (Edge)",
      "url": "http://localhost:9501",
      "webRoot": "${workspaceFolder}"
    },
    {
      "type": "chrome",
      "request": "launch",
      "name": "localhost (Chrome)",
      "url": "http://localhost:9501",
      "webRoot": "${workspaceFolder}"
    }
  ]
}

 

 

5번 줄 : 엣지 브라우저를 구성합니다.

 

7번 줄 : 비주얼 스튜디오 '시작' 버튼에 표시될 이름입니다.

 

8번 줄 : 9601 포트를 사용하여 로컬테스트로 사용합니다.

 

12번 줄 : 크롬 브라우저를 구성합니다.

 

 

 

구성을 바꾸고 저장하면 프로젝트에 적용이 됩니다.

 

 

 

2-2. 테스트 페이지 생성 

테스트를 위한 .html, .ts 파일을 넣을 'src'  폴더를 만들고 아래와 같이 작성합니다.

 

src/index.html

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta http-equiv="Cache-control" content="no-cache">
	<!--<link rel="shortcut icon" href="/favicon.ico">-->
	<!--<base href="/home/">-->
	<title>Visual Studio - Standalone Typescript Template</title>
</head>
<body>
	<h2>Welcome! Standalone Typescript Template</h2>

	<div id="divMain">
	</div>
</body>
</html>

 

 

src/index.ts

export default class App
{
	/** 지금 보여주고 있는 페이지에서 사용할 개체 */
	public PageNow: any = null;

	constructor()
	{
		//메뉴 추가
		let divMain = document.getElementById("divMain");
		divMain.innerHTML = "Test";
	}

}

(window as any).app = new App();

 

 

2-3. package.json 수정 

이것저것 테스트하려고 이렇게 구성했지만 자기가 사용하기 편하게 수정하시면 됩니다.

{
  "name": "Test_TypeScript",
  "private": true,
  "version": "1.0.0",
  "scripts": {
    "start": "webpack-dev-server --mode development --hot",
    "build": "webpack --progress --profile",
    "jsdoc": "jsdoc -c jsdoc.conf README.md",
    "dev": "webpack serve --env development",
    "prod": "webpack --progress --profile --mode production"
  },
  "devDependencies": {
    "@types/node": "^14.14.7",
    "@typescript-eslint/eslint-plugin": "^5.33.0",
    "@typescript-eslint/parser": "^5.33.0",
    "clean-webpack-plugin": "^4.0.0",
    "copy-webpack-plugin": "^11.0.0",
    "docdash": "^2.0.1",
    "eslint": "^8.21.0",
    "html-webpack-plugin": "5.5.0",
    "jsdoc": "^4.0.2",
    "ts-loader": "^9.4.2",
    "typescript": "5.1.6",
    "webpack": "^5.73.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.9.3"
  },
  "eslintConfig": {
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
      "ecmaVersion": "latest",
      "sourceType": "module"
    },
    "plugins": [
      "@typescript-eslint"
    ]
  }
}

 

 

필요 없는 패키지

- jsdoc

- docdash

 

 

2-4. tsconfig.json 수정 

이 파일도 자신의 프로젝트 맞게 구성하면 됩니다.

아래는 예시입니다.

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "lib": [ "es6", "dom" ],
    "sourceMap": true
  },
  "exclude": [
    "node_modules"
  ]
}

 

 

2-5. 웹팩(webpack) 구성 

제가 원래 쓰던 구성을 해야 편해서 넣은 것뿐,

자신의 프로젝트에 맞게 구성하면 됩니다.

 

 

'webpack.config.js' 파일을 생성하고 아래 코드를 넣어줍니다.

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");

//소스 위치
const RootPath = path.resolve(__dirname);
const SrcPath = path.resolve(RootPath, "src");

//웹서버가 사용하는 폴더 이름
const WwwRoot = "build";
//웹서버가 사용하는 폴더 위치
const WwwRootPath = path.resolve(__dirname, WwwRoot);

//템플릿 위치
const IndexHtmlPath = path.resolve(SrcPath, "index.html");
//const IndexHtmlPath = path.resolve(SrcPath, "test01.html");
//결과물 출력 폴더 이름
let OutputFolder = "development";
//결과물 출력 위치
let OutputPath = path.resolve(WwwRootPath, OutputFolder);
//결과물 출력 위치 - 상대 주소
let OutputPath_relative = path.resolve("/", OutputFolder);


module.exports = (env, argv) =>
{
    //릴리즈(프로덕션)인지 여부
    const EnvPrductionIs = argv.mode === "production";
    if (true === EnvPrductionIs)
    {
        //릴리즈 출력 폴더 변경
        OutputFolder = "production";
        OutputPath = path.resolve(WwwRootPath, OutputFolder);
        OutputPath_relative = path.resolve("/", OutputFolder);
    }

    return {
        /** 서비스 모드 */
        mode: EnvPrductionIs ? "production" : "development",
        devtool: "inline-source-map",
        //devtool: "inline-source-map",
        resolve: {
            extensions: [".js", ".ts"]
        },
        output: {// 최종적으로 만들어질 js
            /** 빌드 위치 */
            path: OutputPath,
            /** 웹팩 빌드 후 최종적으로 만들어질 파일 */
            filename: "app.js"
        },
        module: {
            // 모듈 규칙
            rules: [
                // TypeScript 로더 설정
                {
                    test: /\.ts?$/i,
                    exclude: /node_modules/,
                    use: ['ts-loader']
                }
            ]
        },
        plugins: [
            // 빌드한 결과물(예>번들파일)을 HTML에 삽입해주는 플러그인
            new HtmlWebpackPlugin({ template: IndexHtmlPath }),
            // 출력폴더를 비워주는 플러그인
            new CleanWebpackPlugin({
                cleanOnceBeforeBuildPatterns: [
                    '**/*',
                    "!robots.txt",
                    "!Upload"
                ]
            }),

            //그대로 출력폴더에 복사할 파일 지정
            new CopyPlugin({
                patterns: [
                    {
                        //모든 html파일 복사
                        from: "./src/**/*.html",
                        to({ context, absoluteFilename })
                        {
                            //'src/'를 제거
                            let sOutDir = path.relative(context, absoluteFilename).substring(4);
                            //index.html은 리액트가 생성해주므로 여기선 스킵한다.
                            if ("index.html" === sOutDir)
                            {
                                //sOutDir = "index_Temp.html";
                                sOutDir = "";
                            }
                            //console.log("sOutDir : " + sOutDir);
                            return `${sOutDir}`;
                        },
                    },
                ],
                options: {
                    concurrency: 100,
                },
            }),
        ],

        devServer: {
            /** 서비스 포트 */
            port: "9501",
            /** 출력파일의 위치 */
            static: [path.resolve("./", "build/development/")],
            /** 브라우저 열지 여부 */
            //open: true,
            /** 핫리로드 사용여부 */
            hot: true,
            /** 라이브 리로드 사용여부 */
            liveReload: true
        },
    };
}

 

 

104번 줄 : 'launch.json'에서 지정한 포트를 넣어야 합니다.

잘못된 포트가 들어가면 디버깅이 되지 않습니다.

 

 

2-6. 시작 명령 

package.json파일에서 테스트용 웹팩 서버를 실행시키는 명령어를 'dev'로 설정하였습니다.

 

프로젝트에서 시작 버튼을 눌렀을 때 이 명령어가 실행되도록 해야 프론트엔드와 비주얼 스튜디오가 연결됩니다.

 

솔루션 탐색기 > 프로젝트에서 오른쪽 클릭 > 속성 > 배포 > General

의 '시작 명령' 칸에 아래와 같이 넣어줍니다.

npm run dev

 

 

 

3. 테스트하기 

이제 비주얼 스튜디오에 '시작' 버튼을 눌러 실행해 봅시다.

 

잘 됩니다.

 

 

비주얼 스튜디오에서 디버깅을 걸고 실행해 봅시다.

 

디버깅도 잘됩니다.

 

 

마무리 

참고 : 

github - dang-gun/dang-gun-HtmlJavascriptSamples_sln/StandaloneTypescript_Webpack

github - dang-gun/dang-gun-HtmlJavascriptSamples_sln/StandaloneTypescript_Vite

 

이걸 정리해 놓았는지 알고 있었는데 정리해 둔 포스팅이 없었습니다 ㅡ.-;;;

이 설정으로 프로젝트를 여러 개 만들어서 진행하고 있었는데 전혀 모르고 있었다니 ㅎㅎㅎㅎ