> 개발 도구 > VSCode > 본문

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

青灯夜游
풀어 주다: 2021-11-04 19:15:21
앞으로
22837명이 탐색했습니다.

이 기사에서는 평가판 모드의 필요성을 소개하고 VSCode에서 디버깅 모드를 활성화하는 세 가지 방법에 대해 설명하겠습니다.

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

코드 작성이나 유지 관리(버그 수정) 과정에서 간단한 값이나 문제에 대해서는 콘솔을 통해 해결하는 경우도 있습니다. 콘솔이 좋은 방법이라고 생각하더라도 모든 문제를 해결할 수 있는 방법은 아닙니다. 복잡한 유형(참조 유형)의 값은 여전히 ​​디버그 모드(디버거)를 사용해야 합니다. https://juejin.cn/post/7024890041948176398#heading-1bug )的过程中, 对于简单的值或者问题, 我们可以通过console来解决, 甚至有人认为console大法好, 是银弹, 能解决所有问题, 我认为并不是的. 对于想要理清楚代码的执行逻辑, 还有查看复杂类型(引用类型)的值时, 还是得使用到调试模式(debugger) 的。https://juejin.cn/post/7024890041948176398#heading-1

debuggerjs 中的一个语句, 运行到这一行, 如果程序是在调试模式下, 会断点, 就是会停在这一行, 那么我们就可以看到此时的上下文环境, 包括最重要的变量的值, 和调用堆栈. 然后还支持我们单步调试, 或者逐块调试.

平时在浏览器中调试的比较多, 在浏览器中, 只需要打开控制台, 开启了调试模式, 然后遇到debugger语句, 或者自定义的断点, 就会让程序停下来, 进入debug模式.

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

这篇文章主要是会讨论一下在vscode中开启调试模式的方法, 因为我准备写一个vscode插件(敬请期待哈), 调试vscode就在所难免了, 之前的简单调试也肯定满足不了我的需求了, 所以来了解一下vscode的调试模式.

这篇文章不会写调试的技巧, 只是会写一下, vscode怎样开启调试js. 这里是vscode官方文档

再论调试模式的必要性

如果只需要看一个简单的值, 那么完全可以使用console, 因为开启调试模式的成本比较大.

在浏览器中, 因为对象是引用类型的并且浏览器不会直接将对象完成折叠开, 所以如果console之后修改了对象, 再到控制台去看, 得到的将是修改后的对象了

打印后并没有自动全部折叠开

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

去手动折叠开的时候, 浏览器再去读值, 已经变成了修改后的值

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

这种问题的出现, 是因为对象, 所以如果我们转字符串再打印就不会有这个问题, 但是, 不好看, 这里只是举个例子, 有些情况下还是需要用调试模式的.

vscode中开启调试模式

vscode中调试js,ts代码, 有三种方式

  • vscode终端里运行node时, 自动附加, 见3.1.

  • 直接使用vscode提供的debug终端, 见3.2

  • 使用配置文件, 见3.3

1 Auto Attach(自动附加)

vscode的终端里运行node时, 根据不同的选项, 自动判断是否启动debug模式.

一共有 4 种选项, 切换选项的方式也有三种

1.1 切换选项的方式

不管通过哪种设置方式, 更换了设置方式之后, 最好重启一下vscode

debuggerjs의 명령문입니다. 프로그램이 다음 줄에 있으면 이 줄까지 실행됩니다. 디버깅 모드에는 중단점이 있는데, 이는 이 줄에서 중지된다는 것을 의미하므로 이때 가장 중요한 변수의 값을 포함한 컨텍스트를 볼 수 있으며 호출 스택도 지원됩니다. 디버깅.

저는 보통 브라우저에서 디버깅을 많이 하는데, 브라우저에서 콘솔을 열고 디버그 모드를 켜면 가 나타납니다. debugger 문 또는 사용자 정의 인터럽트를 클릭하면 프로그램이 중지되고 debug 모드로 들어갑니다. VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

이 글에서는 주로 vscode에서 디버깅 모드를 활성화하는 방법에 대해 설명합니다. , vscode 플러그인을 작성할 계획이므로(계속 지켜봐 주시기 바랍니다), vscode 디버깅은 불가피합니다. 이전의 간단한 디버깅은 확실히 제 요구 사항을 충족하지 못할 것이므로, vscode의 디버그 모드.

이 문서에서는 디버깅 기술에 대해 작성하지 않지만 vscodejs 디버깅을 활성화하는 방법에 대해 설명합니다. . 여기에 vscode가 있습니다 공식 문서VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

🎜

디버깅 모드의 필요성에 대해 다시 논의

🎜🎜If 간단한 값만 보고 싶다면 콘솔을 사용하면 됩니다. 왜냐하면 디버깅 모드를 켜는 데 드는 비용이 상대적으로 높기 때문입니다. 🎜🎜🎜🎜브라우저에서는 객체가 참조 유형이고 브라우저에서는 개체가 완전히 접히지 않으므로 콘솔 이후 개체를 수정하고 콘솔에 가서 보면 수정된 개체가 나옵니다🎜🎜🎜🎜자동으로 접혀지지 않습니다. 인쇄 후 접기🎜 🎜🎜VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석🎜🎜🎜 수동으로 접으면 브라우저가 그 값을 다시 읽어서 수정된 값이 되었습니다🎜🎜🎜VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석🎜🎜🎜이 문제는 개체 때문에 발생하는 것이므로 문자열로 변환한 후 인쇄하면 문제가 발생하지 않습니다. 그러나 이는 보기에 좋지 않습니다. 일부 경우에는 디버그 모드를 사용해야 합니다.

>vscode

🎜vscode에서 js, ts 코드를 디버그하는 세 가지 방법이 있습니다🎜
  • 🎜vscode 터미널에서 node를 실행하면 자동으로 연결됩니다. 3.1 참조.🎜
  • 🎜vscode에서 제공하는 디버그 터미널을 직접 사용하세요. 3.2 참조🎜
  • 🎜구성 파일 사용, 3.3 참조🎜

🎜1 자동 첨부(자동 첨부)🎜

🎜🎜vscode node 터미널에서 실행하면 다양한 옵션에 따라 디버그 모드 활성화 여부가 자동으로 결정됩니다. 🎜🎜🎜🎜여기에서 총 4가지 옵션이 있으며, 옵션 전환 방법은 3가지가 있습니다🎜🎜

🎜1.1 옵션 전환 방법🎜

🎜🎜어떤 설정 방법을 사용하든 이후에는 설정 방법을 변경하려면 vscode를 다시 시작하여 구성 파일을 수정하여 🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜을 설정하면 더 잘 작동합니다 🎜🎜🎜🎜.

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

구성 파일 settings.json 파일을 연 후settings.json文件之后

// 修改或添加
{
  "debug.javascript.autoAttachFilter": "onlyWithFlag"
}
로그인 후 복사

通过命令(推荐)

使用Ctrl + Shift + P 调出命令(mac或者修改了快捷键的自己找一下),

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

输入attach可以找到它, 选中后可以看到这四个选项, 然后再次选中选项切换到你想要的选项

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

1.2 各个选项的含义

官网的文档没有更新, 默认选项已经不是smart了, 改成disabled

选项含义
始终(always)总是以debug模式启动
智能(smart)只有指定的文件, 才进入debug模式
仅带标志(onlyWithFlag)带有--inspect或者inspect-brk 参数, 以debug模式启动
禁用(disabled)永远不使用debug模式启动

智能(smart)是通过debug.javascript.autoAttachSmartPattern这个配置项指定的是否开启debug模式的文件路径, 默认值是["${workspaceFolder}/**","!**/node_modules/**","**/$KNOWN_TOOLS$/**"]

如果启动了禁用(disabled)模式, 那么node --inspect将也不会进入debug模式, 只能通过下面的方式开启一个debug终端才能进入debug模式, 哎~ vscode 也是个坑货, 不知道啥时间把默认方式改成了disabled, 所以我记得有一次我使用node --inspect没能进入debug模式, 还挺奇怪的, 现在才明白怎么回事.

2 JavaScript Debug Terminal(debug 终端)

直接启动一个debug模式的终端, 在里面启动的node都会进入debug模式.

通过上面的方式(Auto Attach)控制的是vscode中启动的所有终端, 这个只控制它启动的这一个终端.

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

3 Launch Configuration(启动配置)

这个才是重头戏, 我也是主要想了解这个

启动配置是以一种配置文件的方式去设置如何启动debug模式的方式, 它提供了更加配置化去满足运行调试复杂应用

3.1 启动配置的属性

这个配置文件位于当前工作区目录下的.vscode/launch.json, 可以手动创建一个, 或者通过vscode快捷创建一个

1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

然后选择node就好了

1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

必需属性

必需属性, 修改的比较多的应该是name了, 另两个在node中, 一般都不会修改.

Ctrl + Shift + P를 사용하여 명령을 호출하세요(mac 또는 단축키를 수정한 경우 직접 찾으세요), 첨부하면 찾을 수 있어요 선택 후 이 4가지 옵션이 보이는데, 다시 옵션을 선택하면 원하는 옵션으로 전환됩니다VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

1.2 다양한 옵션

属性名含义属性值示例
type调试器类型, 也可以认为是调试的语言node => pwa-node, chrome => pwa-chrome
request启动debug的模式的请求类型,只有两个值launch:启动, attach
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "node调试",
      "port": 9229,
      "request": "attach",
      "skipFiles": ["<node_internals>/**"],
      "type": "pwa-node"
    },
    {
      "type": "pwa-chrome",
      "request": "attach",
      "name": "chrome调试",
      "url": "http://localhost:8080",
      "webRoot": "${workspaceFolder}"
    }
  ]
}
로그인 후 복사
로그인 후 복사

명령으로(권장)

VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석
의 의미 공식 웹사이트의 문서가 업데이트되지 않았습니다. 기본 옵션은 더 이상 smart가 아니지만, 비활성화🎜🎜로 변경되었습니다. 🎜🎜항상(항상)🎜 🎜항상 디버그 모드로 시작🎜🎜🎜🎜스마트(스마트)🎜🎜지정된 항목만 파일은 디버그 모드로 들어갑니다🎜🎜🎜 🎜플래그(onlyWithFlag)가 있는 경우에만🎜🎜--inspect 또는 inspect-brk가 있는 경우 매개변수, debug 모드 시작 🎜🎜🎜🎜Disabled (disabled)🎜🎜절대 debug 모드 시작을 사용하지 마세요🎜🎜🎜🎜 🎜🎜smartdebug 모드 활성화 여부에 대한 파일 경로는 debug.javascript.autoAttachSmartPattern 구성 항목에 의해 지정됩니다. 기본값은 입니다. ["${workspaceFolder}/**","!**/node_modules/**","**/$KNOWN_TOOLS$/**"]🎜🎜🎜 비활성화된 모드가 활성화된 경우 node --inspect디버그 모드로 전환되지 않습니다. 디버그</code를 열어야만 들어갈 수 있습니다. >debug 터미널을 다음과 같은 방법으로 실행하세요. >모드, 안녕하세요~ vscode도 언제 기본 모드를 disabled로 변경했는지 모르겠습니다. , 그래서 node --spect를 사용하여 debug 모드로 진입하지 못했던 기억이 납니다. 이제 무슨 일이 일어났는지 이해하게 되었습니다. data-id="heading-9"> 2 JavaScript 디버그 터미널(디버그 터미널)🎜🎜디버그 모드에서 터미널을 직접 시작하고 node에서 시작하면 디버그 모드로 들어갑니다.🎜🎜🎜위의 방법(Auto Attach)을 통해 에서 시작된 모든 터미널은 >vscode만 제어됩니다. 이 터미널을 시작하세요.🎜🎜VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석🎜

3 실행 구성

🎜🎜이것은 하이라이트이며, 주로 그것에 대해 더 알고 싶습니다. 이 🎜🎜🎜 시작 구성은 디버그 모드를 시작하는 방법을 설정하는 구성 파일입니다. 요구 사항을 충족하기 위해 추가 구성을 제공합니다. 복잡한 애플리케이션 실행 및 디버깅🎜

3.1 실행 구성 속성

🎜🎜이 구성 파일은 에 있습니다. .vscode/launch.json 현재 작업 공간 디렉터리에서 수동으로 만들거나 vscode🎜🎜1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석🎜🎜🎜그런 다음 노드🎜를 선택하세요. 🎜1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석 🎜

필수 속성

🎜🎜필수 속성, 가장 많이 수정된 속성은 name이어야 하고 나머지 두 개는 다음과 같습니다. 노드에서는 일반적으로 수정되지 않습니다. 🎜
옵션의미
🎜🎜🎜type🎜🎜디버거 유형, 디버깅 언어로도 간주될 수 있습니다🎜🎜node => >, chrome => pwa-chrome🎜🎜🎜🎜request🎜🎜디버그 모드 실행을 위한 요청 유형에는 두 가지 값만 있습니다🎜🎜launch</code >: start, < code>attach: Attach 🎜🎜🎜🎜name🎜🎜사용자가 🎜🎜custom을 구별하기 위해 사용하는 이 시작 구성의 이름입니다. 스스로 이해하고 사용하세요🎜🎜 🎜🎜
request

我们常用的是 launch , 所以这里只是讨论了 launch 的使用.

对于 launchattach 的区别, 可以看 B 站上这个大佬的视频, 讲解地很好. 程序员阿汤 => 介绍 launch.json

name

name的含义是: 一个launch.json中可以配置多个启动配置, 所以需要给每个启动配置起个名字, 用于区分

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "node调试",
      "port": 9229,
      "request": "attach",
      "skipFiles": ["<node_internals>/**"],
      "type": "pwa-node"
    },
    {
      "type": "pwa-chrome",
      "request": "attach",
      "name": "chrome调试",
      "url": "http://localhost:8080",
      "webRoot": "${workspaceFolder}"
    }
  ]
}
로그인 후 복사
로그인 후 복사

1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

选中某一个, 然后可以使用快捷键f5, 快速启动, 或者点击运行图标

1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

launchattach都支持的属性

속성 이름의미속성 값 예
属性含义
outFiles指定Source maps文件所在路径
resolveSourceMapLocations也是指定与Source maps相关的路径
timeout附加的超时时间, 超时就放弃
stopOnEntry项目启动起来, 立即debugger一下, 就是相当于在代码的第一行加了一个debugger
localRoot这个是用来远程调试用的, 我就先不了解它了...
remoteRoot这个是用来远程调试用的, 我就先不了解它了...
smartStep自动跳过没有映射到的源文件
skipFiles指定单步跳过的文件, 就是debugger不跟进去看的源代码
trace开启会将一些调试输出保存到vscode指定的文件中
skipFiles

(这个挺有用的, 有些代码不想跟进去看, 但是经常点快了, 就进去了..., 可以把这些文件排除掉, <node_internals>/**/*.js配置上这个, 可以跳过node核心模块的代码.)

trace

开启trace

1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

launch支持的属性

属性含义
program启动项目的入口文件地址(就是要执行的js的路径)
args相当于命令行参数(下面有详解)
cwd指定程序启动的路径(下面有详解)
runtimeExecutable指定可执行程序的启动路径(下面有详解)
runtimeArgs给可执行程序的参数(下面有详解)
env指定环境变量(下面有详解)
args

"args": ["aaa", "bbb"] :在命令行传递参数的方式, 在node中可以通过process.argv拿到

1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

cwd

"cwd": "${workspaceFolder}/demo", 配置这个路径, 在node中, 相当于指定了process.cwd()的路径

1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

runtimeExecutable

这个可以指定启动的程序名, 比如使用nodemon启动, 或者指定路径, 比如你有 3 个版本的 node 想启动调试看看各个版本的差异, 就不需要切换全局的 node 版本, 只需要设置多个配置项就行啦. 这样很方便的.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "v10 版本启动",
      "program": "${workspaceFolder}/demo.js",
      "request": "launch",
      "type": "pwa-node",
      "runtimeExecutable": "C:\\Program Files\\nodejsv10\\node.js" // 这里是 v10 版本的node路径
    },
    {
      "name": "v11 版本启动",
      "program": "${workspaceFolder}/demo.js",
      "request": "launch",
      "type": "pwa-node",
      "runtimeExecutable": "C:\\Program Files\\nodejsv11\\node.js" // 这里是 v11 版本的node路径
    },
    {
      "name": "v12 版本启动",
      "program": "${workspaceFolder}/demo.js",
      "request": "launch",
      "type": "pwa-node",
      "runtimeExecutable": "C:\\Program Files\\nodejsv12\\node.js" // 这里是 v12 版本的node路径
    }
  ]
}
로그인 후 복사
runtimeArgs

这个里面写的参数会紧跟在可执行程序后面, 在node程序中, node会将它后面的第一个参数视为它要执行的文件的路径, 所以需要有所调整.

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "v10 版本启动",
      "program": "${workspaceFolder}/demo.js", // 这个现在已经不是 node 的执行文件地址了, 它只是一个参数了
      "request": "launch",
      "type": "pwa-node",
      "args": ["args1", "args2"],
      "runtimeArgs": ["${workspaceFolder}/demo.js", "runtimeArgs2"] // 因为它紧跟在 可执行程序后面, 所以它的第一个参数需要设置为它要执行的文件的地址
      // 如果它是 --experimental-modules 类型参数就没事了, 因为node会把它解析成参数, 这个参数的含义是 启动 es 模块支持. 接下来我会写一篇 js 的模块化的文章, 敬请期待哈
    }
  ]
}
// 启动的命令行是
// C:\Program Files\nodejs\node.exe E:\font-end/demo.js runtimeArgs2 .\demo.js args1 args2
로그인 후 복사

1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

这个参数在弄成 npm 启动项目的时候, 比较有用

env
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "v10 版本启动",
      "program": "${workspaceFolder}/demo.js",
      "request": "launch",
      "type": "pwa-node",
      "env": {
        "NODE_ENV": "prod"
      }
    }
  ]
}
로그인 후 복사

1VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석

attach支持的属性

我们常用的是 launch 方式启动, 就先不了解 attach 的方式启动了.

总结

对于如何在vscode中启动debug模式, 应该是比较清楚的了

vscode中, 一共有三种方式启动debug调试, 分别是

  • 自动附加(影响全局的终端), 如果对自己电脑性能有自信, 设置为always. 命令行运行进入debug模式.

  • 强制开启(只影响这一个终端), 如果不方便配置开启全局的自动debug, 使用这种方式进入debug, 也是比较放便的, 就是重新开启这个debug终端之后, 需要cd到需要运行的js文件目录, 比较麻烦. 命令行运行进入debug模式.

  • 配置开启(功能强大, 适合调试复杂应用),配置好.vscode/launch.json后, f5启动进入debug模式

// 比较完整一个 launch.json 配置
{
  // 使用 IntelliSense 了解相关属性。
  // 悬停以查看现有属性的描述。
  // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "v10 版本启动", // 配置名称
      "program": "${workspaceFolder}/demo.js", // 项目启动入口文件
      "request": "launch", // `debug`模式的请求方式
      "stopOnEntry": true, // 项目启动, 立即`debugger`一下
      "type": "pwa-node", // 调试器类型
      "env": {
        // 环境变量
        "NODE_ENV": "prod"
      },
      "args": ["aaaa"], // 启动命令时跟在 program 后的参数
      "skipFiles": [
        // 指定单步调试不进去的文件
        "<node_internals>/**" // node 的核心库, 比如`require`
      ],
      "cwd": "${workspaceFolder}", // 指定可执行程序的启动路径, process.cwd(),
      "runtimeExecutable": "nodemon", // 指定可执行程序名称, 或者路径, 在这里 type 为 pwa-node 默认值是 node
      "runtimeArgs": ["--experimental-modules"] // 启动命令时, 跟在 runtimeExecutable 后的参数
    }
  ]
}
로그인 후 복사

最后

这里已经有三个坑了, 模块化,调试技巧, vscode插件开发, 我目前更想先写一个vscode插件,敬请期待.

感觉这篇文章能改到你启发的, 希望给个点赞, 评论, 收藏, 关注...

更多编程相关知识,请访问:编程视频!!

위 내용은 VSCode에서 디버깅 모드를 활성화하는 방법은 무엇입니까? 세 가지 방법에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿