├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .dockerignore ├── .editorconfig ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── README.md ├── docs ├── 1.liveshare.md ├── 2.unittest.md ├── 3.server.md ├── 4.frontend.md ├── README.md ├── application.png ├── browser_bind.png ├── code_comment.png ├── comment_thread.png ├── focus.png ├── follow.png ├── following_pin.png ├── frontend_webapi.png ├── functions.png ├── interface.png └── share_server.png ├── out └── .gitkeep ├── package-lock.json ├── package.json ├── public └── html │ ├── index.html │ └── js │ └── .gitignore ├── src ├── frontend │ ├── api │ │ └── task.ts │ ├── index.ts │ └── views │ │ ├── newTask.ts │ │ └── taskList.ts ├── model │ └── task │ │ ├── repository.ts │ │ └── task.ts └── server │ ├── api.ts │ └── main.ts ├── tests └── model │ └── task │ └── repository_test.ts ├── tsconfig.json ├── tslint.json └── webpack.config.js /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # copy of https://github.com/microsoft/vscode-dev-containers/blob/master/containers/typescript-node-12/.devcontainer/Dockerfile 2 | 3 | #------------------------------------------------------------------------------------------------------------- 4 | # Copyright (c) Microsoft Corporation. All rights reserved. 5 | # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. 6 | #------------------------------------------------------------------------------------------------------------- 7 | 8 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:12 9 | 10 | # The javascript-node image includes a non-root node user with sudo access. Use 11 | # the "remoteUser" property in devcontainer.json to use it. On Linux, the container 12 | # user's GID/UIDs will be updated to match your local UID/GID when using the image 13 | # or dockerFile property. Update USER_UID/USER_GID below if you are using the 14 | # dockerComposeFile property or want the image itself to start with different ID 15 | # values. See https://aka.ms/vscode-remote/containers/non-root-user for details. 16 | ARG USERNAME=node 17 | ARG USER_UID=1000 18 | ARG USER_GID=$USER_UID 19 | 20 | # Alter node user as needed, install tslint, typescript. eslint is installed by javascript image 21 | RUN if [ "$USER_GID" != "1000" ] || [ "$USER_UID" != "1000" ]; then \ 22 | groupmod --gid $USER_GID $USERNAME \ 23 | && usermod --uid $USER_UID --gid $USER_GID $USERNAME \ 24 | && chown -R $USER_UID:$USER_GID /home/$USERNAME; \ 25 | fi \ 26 | # 27 | # Install tslint, typescript. eslint is installed by javascript image 28 | && sudo -u ${USERNAME} npm install -g tslint typescript 29 | 30 | # ********************************************************************* 31 | # * Uncomment this section to use RUN to install other dependencies. * 32 | # * See https://aka.ms/vscode-remote/containers/dockerfile-run * 33 | # ********************************************************************* 34 | # ENV DEBIAN_FRONTEND=noninteractive 35 | # RUN apt-get update \ 36 | # && apt-get -y install --no-install-recommends \ 37 | # # 38 | # # Clean up 39 | # && apt-get autoremove -y \ 40 | # && apt-get clean -y \ 41 | # && rm -rf /var/lib/apt/lists/* 42 | # ENV DEBIAN_FRONTEND=dialog 43 | 44 | # Uncomment to default to non-root user 45 | # USER $USER_UID 46 | RUN apt-get update && apt-get install -y jq 47 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | // copy from https://github.com/microsoft/vscode-dev-containers/blob/master/containers/typescript-node-12/.devcontainer/devcontainer.json 3 | "name": "Node.js 12 & TypeScript", 4 | "dockerFile": "Dockerfile", 5 | // Set *default* container specific settings.json values on container create. 6 | "settings": { 7 | "terminal.integrated.shell.linux": "/bin/bash" 8 | }, 9 | // Add the IDs of extensions you want installed when the container is created. 10 | "extensions": [ 11 | "streetsidesoftware.code-spell-checker", 12 | "msjsdiag.debugger-for-chrome", 13 | "editorconfig.editorconfig", 14 | "esbenp.prettier-vscode", 15 | "hbenl.vscode-test-explorer-liveshare", 16 | "wayou.vscode-todo-highlight", 17 | "ms-vsliveshare.vsliveshare-pack", 18 | "hbenl.vscode-test-explorer", 19 | "hbenl.vscode-mocha-test-adapter", 20 | "redhat.vscode-yaml", 21 | ], 22 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 23 | "forwardPorts": [ 24 | 8080 25 | ], 26 | // Use 'postCreateCommand' to run commands after the container is created. 27 | "postCreateCommand": "npm install" 28 | // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root. 29 | // "remoteUser": "node" 30 | } -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out 3 | tmp 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | 8 | [*.ts] 9 | indent_style = space 10 | indent_size = 4 11 | 12 | [*.yaml] 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.md] 17 | indent_style = space 18 | indent_size = 2 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | tmp 4 | .mypy_cache 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "streetsidesoftware.code-spell-checker", 4 | "msjsdiag.debugger-for-chrome", 5 | "editorconfig.editorconfig", 6 | "esbenp.prettier-vscode", 7 | "hbenl.vscode-test-explorer-liveshare", 8 | "wayou.vscode-todo-highlight", 9 | "ms-vsliveshare.vsliveshare-pack", 10 | "hbenl.vscode-test-explorer", 11 | "hbenl.vscode-mocha-test-adapter", 12 | "redhat.vscode-yaml", 13 | ] 14 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "launch", 7 | "name": "Launch Server", 8 | "env": { 9 | "PORT": "8080" 10 | }, 11 | "preLaunchTask": "tsc build", 12 | "program": "${workspaceFolder}/out/src/server/main.js", 13 | "outFiles": ["${workspaceFolder}/**/*.js"] 14 | }, 15 | { 16 | "type": "node", 17 | "request": "launch", 18 | "name": "Launch Server(ts-node)", 19 | "env": { 20 | "PORT": "8080" 21 | }, 22 | "runtimeArgs": ["-r", "ts-node/register"], 23 | "args": ["${workspaceFolder}/src/server/main.ts"] 24 | }, 25 | { 26 | "type": "chrome", 27 | "request": "launch", 28 | "name": "Launch Chrome", 29 | "url": "http://localhost:8080/index.html", 30 | "webRoot": "${workspaceFolder}/public/html", 31 | "preLaunchTask": "webpack build", 32 | "sourceMapPathOverrides": { 33 | "webpack:///./src/*": "${workspaceRoot}/src/*" 34 | }, 35 | "sourceMaps": true 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "yaml.schemas": { 3 | "Kubernetes": ["environment/manifests/**/**.yaml"], 4 | "https://raw.githubusercontent.com/docker/compose/master/compose/config/config_schema_v3.8.json": [ 5 | "docker-compose.yaml", 6 | "docker-compose.yml" 7 | ] 8 | }, 9 | "files.encoding": "utf8", 10 | "files.autoGuessEncoding": false, 11 | 12 | // 非表示にするファイル 13 | "files.exclude": { 14 | "**/.git": true, 15 | "**/.svn": true, 16 | "**/.hg": true, 17 | "**/CVS": true, 18 | "**/.DS_Store": true, 19 | "tmp": true, 20 | "node_modules": true, 21 | ".pytest_cache": true 22 | }, 23 | // 検索で表示させないファイル 24 | "search.exclude": { 25 | "users": true, 26 | "tmp": true, 27 | "**/node_modules": true, 28 | "**/bower_components": true, 29 | "**/*.code-search": true 30 | }, 31 | // --- mocha の設定 --- 32 | // Mochaはnode_modules内のパッケージを使う 33 | "mochaExplorer.mochaPath": "./node_modules/mocha", 34 | 35 | // testsフォルダー下のソースコードを指定する 36 | "mochaExplorer.files": "tests/**/*.ts", 37 | 38 | // TypeScriptを使うため、ts-nodeを使う 39 | "mochaExplorer.require": ["ts-node/register"], 40 | 41 | // ワークスペースのフォルダーで実行する 42 | "mochaExplorer.cwd": "./", 43 | 44 | // ワークスペース内のファイルで絶対参照を使うための設定 45 | "mochaExplorer.env": { 46 | "NODE_PATH": "./" 47 | }, 48 | 49 | // コードレンズを有効にする 50 | "editor.codeLens": true, 51 | "testExplorer.codeLens": true, 52 | "typescript.referencesCodeLens.enabled": true, 53 | "typescript.implementationsCodeLens.enabled": true 54 | } 55 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "typescript", 6 | "label": "tsc watch", 7 | "tsconfig": "tsconfig.json", 8 | "problemMatcher": ["$tsc"] 9 | }, 10 | { 11 | "type": "typescript", 12 | "label": "tsc build", 13 | "tsconfig": "tsconfig.json", 14 | "problemMatcher": ["$tsc"] 15 | }, 16 | { 17 | "label": "webpack build", 18 | "command": ["${workspaceFolder}/node_modules/.bin/webpack"], 19 | "args": [ 20 | "./src/frontend/index.ts", 21 | "--output", 22 | "./public/html/js/index.js" 23 | ], 24 | "type": "shell", 25 | "group": { 26 | "kind": "build", 27 | "isDefault": true 28 | }, 29 | "problemMatcher": ["$tsc"] 30 | }, 31 | { 32 | "label": "webpack build (watch)", 33 | "command": ["${workspaceFolder}/node_modules/.bin/webpack"], 34 | "args": [ 35 | "-w", 36 | "./src/frontend/index.ts", 37 | "--output", 38 | "./public/html/js/index.js" 39 | ], 40 | "type": "shell", 41 | "problemMatcher": ["$tsc"], 42 | "isBackground": true, 43 | "runOptions": { 44 | "runOn": "folderOpen" 45 | } 46 | }, 47 | { 48 | "type": "typescript", 49 | "tsconfig": "tsconfig.json", 50 | "option": "watch", 51 | "problemMatcher": ["$tsc-watch"], 52 | "group": "build" 53 | } 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VSCode TypeScript 開発体験 ハンズオン 2 | 3 | ## ゴール 4 | 5 | - Type Script の役割を理解し、VSCode で開発ができるようになること 6 | - VSCode で Type Script でサーバアプリケーションをコンパイル、デバッグができる 7 | - VSCode で Type Script で Web フロントエンドのアプリケーションをコンパイル、デバッグできる 8 | 9 | ## 解説すること 10 | 11 | - Type Script とは何をするコンパイラであるか 12 | - VSCode で Node.js 上で動作する Type Script の開発環境の構築方法、開発方法、デバッグ方法 13 | - VSCode で Chrome 上で動作する Type Script の開発環境の構築方法、開発方法、デバッグ方法 14 | 15 | ## 解説しないこと 16 | 17 | - Node.js 、 npm のインストール方法、及び使い方(コマンドで紹介します) 18 | - Vue.js の使い方(完成品ソースコードを提供します) 19 | - VSCode のインストール方法([公式ドキュメント(英語)](https://code.visualstudio.com/docs/setup/setup-overview)、[KC さんの記事](https://employment.en-japan.com/engineerhub/entry/2019/06/21/103000)、もしくは書籍[Visual Studio Code 実践ガイド](https://gihyo.jp/book/2020/978-4-297-11201-1)を参照下さい) 20 | 21 | ## 準備が必要なもの 22 | 23 | - Windows、もしくは MacOS の開発用 PC(Linux は Zoom が正常に動作しないため不可、クライアントは Windows/MacOS でリモート開発機能で Linxu の SSH 接続先環境を用意している、リモートコンテナ機能の使用は可) 24 | - Windows の場合、[Git のインストール](https://gitforwindows.org/) 25 | - [VS Code Meetup Slack への参加(こちらのページに案内リンクがあります)](https://vscode.connpass.com/) 26 | - [Zoom クライアントのインストール](https://zoom.us/download)、及び音声、画面共有のテスト 27 | - [Visual Studio Code のインストール] 28 | - [Node.js のインストール](https://nodejs.org/ja/) 29 | - [Chrome ブラウザのインストール](https://www.google.co.jp/chrome/) 30 | 31 | ### VSCode で準備が必要なもの 32 | 33 | 以下の拡張機能を、事前にインストールして下さい 34 | 35 | - [Live Share](https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare-pack) 36 | - 事前に、"Start collaboration session..." をクリックし、Microsoft アカウント、Github アカウントとリンクさせておいて下さい 37 | - [Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) 38 | 39 | ## ご容赦いただきたいこと 40 | 41 | - このハンズオンは有志の実験的取り組みです。至らない点など多数あるかと思いますが、参加者同士でコミュニケーションをとっていただき、一緒に解決できればと思います。 42 | - Live Share を使ってのハンズオンなど、主催者としても初めての取り組みを行っています。ご不便をおかけする点も多いと思いますが、ご協力いただければと思います。 43 | - Live Share は、Share の仕方を誤ると、ターミナルを横取りできたり、ターミナルやプログラムを介して、個人の機密情報にアクセスすることができうるプロダクトです。自己責任の上、注意して使用して下さい。また、もしアクセス可能だとしても他人の情報にはアクセスしないようにして下さい。 44 | - このハンズオンの内容には、書籍[Visual Studio Code 実践ガイド](https://gihyo.jp/book/2020/978-4-297-11201-1)の内容が含まれます。資料は用意するため、購入は必須はありませんが、購入を検討いただければ幸いです。 45 | - 本ハンズオンの内容を、de:code などカンファレンスで紹介することがあります。 46 | 47 | ## アジェンダ 48 | 49 | 1. Live Share 機能を使って、環境を公開してみよう 50 | 2. Type Script のプロジェクトをセットアップしよう 51 | 3. Type Script の Node.js アプリケーションをデバッグしよう 52 | 4. Type Script の Vue.js アプリケーションをセットアップしよう 53 | 5. フロントエンドとサーバサイドを同時にデバッグしよう 54 | 55 | ## コミュニケーションのとり方 56 | 57 | - ハンズオン中は Zoom を繋ぎっぱなしにしてください。morimoto さんと呼んでいただければ、応答します! 58 | - VSCode Meetup Slack にチャンネルを開設して、筆談が良い場合、 59 | - Live Share を活用しましょう! Live Share で "Start collaboration session..." をクリックすると、クリップボードに Live Share のリンクが作成されます。これを Slack に共有して下さい。Live Share で実際のコードを見ながら聞きに行きます 60 | -------------------------------------------------------------------------------- /docs/1.liveshare.md: -------------------------------------------------------------------------------- 1 | # Live Share 2 | 3 | How To があれば、ここに追記して下さい! 4 | 5 | ## できること 6 | 7 | 1. ホストの人が VSCode のワークスペースに入って、共同編集することができる。 8 | 9 | - 人のタイプするカーソルを見ることができる 10 | 11 | 2. コードにコメントを付ける 12 | 13 | - コメントの一覧がパネルに表示される 14 | - コメントにはリプライができる 15 | 16 | ![](./code_comment.png) 17 | 18 | ![](./comment_thread.png) 19 | 20 | 注意: スレッドに表示される右上の ✕ ボタンは**削除**のボタンです。 21 | 22 | 3. 人のカーソルを追いかけることができる 23 | 24 | ![](./follow.png) 25 | 26 | 追いかけるモード中は、エディター右上のピンの色が変わります。 27 | 28 | ![](./following_pin.png) 29 | 30 | 4. 自分のカーソルを追いかけさせることができる 31 | 32 | ![](./focus.png) 33 | 34 | 5. ポートを共有できる(Share Server から) 35 | 36 | ![](./share_server.png) 37 | 38 | 6. Debug Session を共有できる 39 | 7. ターミナルを共有できる 40 | 8. 音声共有ができる 41 | 9. 細かい権限設定ができる 42 | 43 | - 他の人を呼ぶことを許可する 44 | - Terminal の実行許可 45 | - Task、Debug の設定編集、実行許可 46 | 47 | ## 注意すること 48 | 49 | - Task、Terminal、Debug の設定を不用意に開放しない 50 | - 共有リンクを信頼の置ける人にだけ共有する 51 | 52 | ## Share を始める 53 | 54 | - (1) (1 度だけ) コマンド "Microsoft Account: Sign on" を実行し、Microsoft アカウントと連携する 55 | - (2) コマンド "Live Share: Start Collaborate Session (Share)" を実行 56 | - (3) Clip Board にリンクがコピーされるので、このリンクを共有する 57 | 58 | ## 人のセッションに入る 59 | 60 | - (1) 共有されたリンクをクリックする 61 | 62 | or 63 | 64 | - (1) コマンド "Live Share: Join Collaboration Session" を実行 65 | - (2) 共有されたリンクをペーストする 66 | 67 | ## 今日の進め方 68 | 69 | コーディングはなるべく Live Share 環境で行って下さい。 70 | 71 | デバッグが Live Share 環境では実行できないため、リモート SSH 機能を使って以下のサーバにログインして下さい。 72 | 73 | コマンド "Remote-SSH: Open Configuration File..." で .ssh/config を開き、以下のように入力をして下さい。 74 | IdentityFile は Slack で共有したファイルを指定して下さい。 75 | 76 | For MacOS / Linux 77 | 78 | ``` 79 | HOST handson 80 | HostName 52.185.173.228 81 | User ubuntu 82 | IdentityFile /home/nnyn/Downloads/hanson_key 83 | ``` 84 | 85 | For Windows 86 | 87 | ``` 88 | Host handson 89 | HostName 52.185.173.228 90 | User ubuntu 91 | IdentityFile "C:\Users\nnyn\Downloads\hanson_key" 92 | ``` 93 | 94 | コマンド "Remote-SSH: Connect to Host..." を実行し、"handson"を選んで下さい。 95 | 96 | 最初はフォルダーが開かれていない状態になっています。コマンド "File: Open Folder..."を実行し、`/home/ubuntu/main/`を開いて下さい。 97 | -------------------------------------------------------------------------------- /docs/2.unittest.md: -------------------------------------------------------------------------------- 1 | # Type Script のコンパイルとユニットテスト 2 | 3 | ## タスク管理アプリ 4 | 5 | 『Visual Studio Code 実践ガイド』より 6 | 7 | ![](./application.png) 8 | 9 | ![](./functions.png) 10 | 11 | ![](./frontend_webapi.png) 12 | 13 | ![](./interface.png) 14 | 15 | ## コードの構成 16 | 17 | ``` 18 | todo-list 19 | |-- src ……TypeScriptのコード 20 | | |-- model ……フロントエンド、Web APIで共通のモデル 21 | | |-- server ……Web API 22 | | |-- frontend ……フロントエンド 23 | | `-- tests ……TypeScriptのユニットテスト 24 | | `-- model ……モデルのテストコード 25 | |-- out ……TypeScriptの出力 26 | |-- public 27 | | `-- html 28 | | |-- js ……Webpackの出力先 29 | | `-- index.html ……ドキュメントルート 30 | `-- node_modules ……利用するnpmパッケージの格納フォルダー(自動生成) 31 | ``` 32 | 33 | ## 設定ファイル類 34 | 35 | - package.json : npm package 36 | - tsconfig.json : Type Script の設定 37 | - webpack.config.js : webpack の設定 38 | - tslint.json : webpack の設定 39 | - .vscode/settings.json : プロジェクトの設定ファイル 40 | - .vscode/launch.json : デバッグ実行定義 41 | - .vscode/tasks.json : タスク設定 42 | 43 | ## Type Script をコンパイルする 44 | 45 | コマンドなら 46 | 47 | ``` 48 | ./node_modules/.bin/tsc 49 | ``` 50 | 51 | [VS Code Task](../.vscode/tasks.json)なら 52 | 53 | ```json 54 | { 55 | "version": "2.0.0", 56 | "tasks": [ 57 | { 58 | "type": "typescript", 59 | "label": "tsc build", 60 | "tsconfig": "tsconfig.json", 61 | "problemMatcher": ["$tsc"] 62 | } 63 | ] 64 | } 65 | ``` 66 | 67 | [バックグランド実行のタスク](../.vscode/tasks.json) 68 | 69 | ```json 70 | { 71 | "version": "2.0.0", 72 | "tasks": [ 73 | { 74 | "type": "typescript", 75 | "label": "tsc watch", 76 | "tsconfig": "tsconfig.json", 77 | "problemMatcher": ["$tsc"] 78 | } 79 | ] 80 | } 81 | ``` 82 | 83 | ## ロジックの実装 84 | 85 | 課題 1 タスクを完了にする関数を実装してみて下さい。 86 | 87 | タスクのリストは`Repository.tasks`に格納されていて、`ITask.done`プロパティにタスクが完了したかどうかのフラグを持っています。 88 | 89 | - ITask [src/model/task/morimoto_task.ts](../src/model/task/morimoto_task.ts) 90 | - Repository [src/model/task/morimoto_repository.ts](../src/model/task/morimoto_repository.ts) 91 | - DoneTask 92 | 93 | ## ユニットテスト 94 | 95 | ユニットテストフレームワーク[mocha](https://mochajs.org/)を使います。 96 | 97 | [tests/model/task/morimoto_repository_test.ts](../tests/model/task/morimoto_repository_test.ts) 98 | 99 | コマンドなら 100 | 101 | ``` 102 | NODE_PATH=./ ./node_modules/.bin/mocha -r ts-node/register tests/model/task/repository_test.ts 103 | ``` 104 | 105 | だいたいの Nodejs のツールが絡んでいても、`-r ts-node/register`を使うと TypeScript のまま引数に渡せて便利。 106 | 107 | 課題 2 CodeLens を使って実行、及びデバッグ実行してみて下さい。TypeScript がデバッグできることを確認して下さい。 108 | 109 | 課題 3 Test Explorer タブ を使って、実行、及びデバッグ実行してみて下さい。 110 | 111 | [tsconfig.json](../tsconfig.json#L22) `"sourceMap": true`が有効になっていると、xxx.js.map ファイルが作られ、それをもとに Type Script を Java Script のようにデバッグできます。 112 | 113 | [mocha 周りの設定](../.vscode/settings.json#L35) 114 | 115 | ```json 116 | { 117 | // --- mocha の設定 --- 118 | // Mochaはnode_modules内のパッケージを使う 119 | "mochaExplorer.mochaPath": "./node_modules/mocha", 120 | 121 | // testsフォルダー下のソースコードを指定する 122 | "mochaExplorer.files": "tests/**/*.ts", 123 | 124 | // TypeScriptを使うため、ts-nodeを使う 125 | "mochaExplorer.require": ["ts-node/register"], 126 | 127 | // ワークスペースのフォルダーで実行する 128 | "mochaExplorer.cwd": "./", 129 | 130 | // ワークスペース内のファイルで絶対参照を使うための設定 131 | "mochaExplorer.env": { 132 | "NODE_PATH": "./" 133 | } 134 | } 135 | ``` 136 | -------------------------------------------------------------------------------- /docs/3.server.md: -------------------------------------------------------------------------------- 1 | # 3. サーバ API の実装とデバッグ 2 | 3 | ## 実装 4 | 5 | [src/server/morimoto_main.ts](../src/server/morimoto_main.ts) 実際に実行の起点となるエントリーポイント 6 | 7 | [src/server/morimoto_api.ts](../src/server/morimoto_api.ts) 8 | API へのリクエストを Repository に流す API クラス 9 | 10 | API クラスが担っていること 11 | 12 | - HTTP リクエストのメソッド(GET、POST)と、パスから、ロジックとの対応関係を示すルーティング [API.routing()](../src/server/morimoto_api.ts#L45) 13 | - 実際にロジックを呼ぶ処理 [API.list()、API.create()、API.done()](../src/server/morimoto_api.ts#L60) 14 | 15 | 課題 4 タスクの完了を実装して下さい。 16 | 17 | - [API.done()](../src/server/morimoto_api.ts#L77) 18 | 19 | ## サーバを起動する 20 | 21 | コマンドなら 22 | 23 | ``` 24 | node out/src/server/main.js 25 | ``` 26 | 27 | ``` 28 | ./node_modules/.bin/ts-node src/server/main.js 29 | ``` 30 | 31 | デバッグ実行する [.vscode/launch.json](../.vscode/launch.json) 32 | 33 | デバッグにはスニペットを使えます。ここでも、ts-node が使えます。 34 | 35 | ```json 36 | { 37 | "version": "0.2.0", 38 | "configurations": [ 39 | { 40 | "type": "node", 41 | "request": "launch", 42 | "name": "morimoto Launch Server", 43 | "preLaunchTask": "tsc build", 44 | "program": "${workspaceFolder}/out/src/server/morimoto_main.js", 45 | "outFiles": ["${workspaceFolder}/**/*.js"] 46 | }, 47 | { 48 | "type": "node", 49 | "request": "launch", 50 | "name": "morimoto Launch Server(ts-node)", 51 | "runtimeArgs": ["-r", "ts-node/register"], 52 | "args": ["${workspaceFolder}/src/server/morimoto_main.ts"] 53 | } 54 | ] 55 | } 56 | ``` 57 | 58 | ``` 59 | curl http://localhost:8080/api/tasks | jq 60 | ``` 61 | 62 | ```json 63 | [ 64 | { 65 | "id": 1, 66 | "text": "task1", 67 | "done": false 68 | }, 69 | { 70 | "id": 2, 71 | "text": "task2", 72 | "done": false 73 | } 74 | ] 75 | ``` 76 | 77 | タスクの追加 78 | 79 | ``` 80 | curl \ 81 | -H 'Content-Type: application/json' \ 82 | -d '{"id":0,"text":"new task"}' \ 83 | -XPOST \ 84 | http://localhost:8080/api/tasks | jq 85 | ``` 86 | 87 | ```json 88 | { 89 | "id": 3 90 | } 91 | ``` 92 | 93 | タスクの完了 94 | 95 | ``` 96 | curl \ 97 | -H 'Content-Type: application/json' \ 98 | -XPOST \ 99 | http://localhost:8080/api/tasks/1/done | jq 100 | ``` 101 | 102 | 課題 5 デバッグ実行で起動し、curl で呼び出して、タスクの完了をデバッグ実行してみて下さい。 103 | -------------------------------------------------------------------------------- /docs/4.frontend.md: -------------------------------------------------------------------------------- 1 | # 4. Frontend のデバッグ 2 | 3 | ## コードの構成 4 | 5 | ``` 6 | |- src 7 | | `- frontend 8 | | |- morimoto_index.ts : エントリーポイント 9 | | |- api 10 | | | `- morimoto_task.ts : REST APIにアクセスする 11 | | `- views/ Vue.jsオブジェクト 12 | | |- morimoto_newTask.ts : タスク作成UI 13 | | `- morimoto_taskList.ts : タスク一覧と、タスクカード 14 | `- public 15 | `- html 16 | |- js 17 | | `- morimoto_index.js : webpackで生成したJS 18 | `- morimoto_index.html : HTML 19 | ``` 20 | 21 | ## webpack 22 | 23 | webpack を使うと、commonjs 形式のモジュール(NodeJS で使われている)を、Web Browser でも実行できるように、依存関係を 1 つのソースコードにまとめてくれます。 24 | 設定ファイルは[webpack.config.js](../webpack.config.js)で、Type Script のコンパイルを行わせるようにしています。 25 | 26 | ``` 27 | ./node_modules/.bin/webpack src/frontend/ ./src/frontend/morimoto_index.ts --output ./public/html/js/morimoto_index.js 28 | ``` 29 | 30 | Task 化すると、以下のようになります。 31 | 32 | ```json 33 | { 34 | "version": "2.0.0", 35 | "tasks": [ 36 | { 37 | "label": "morimoto webpack build", 38 | "command": ["${workspaceFolder}/node_modules/.bin/webpack"], 39 | "args": [ 40 | "./src/frontend/morimoto_index.ts", 41 | "--output", 42 | "./public/html/js/morimoto_index.js" 43 | ], 44 | "type": "shell", 45 | "group": { 46 | "kind": "build", 47 | "isDefault": true 48 | }, 49 | "problemMatcher": ["$tsc"] 50 | } 51 | ] 52 | } 53 | ``` 54 | 55 | また、バックグラウンドプロセスでファイルの変更を検知し、自動でビルドする`webpack -w`というオプションがあります。 56 | これを用いて Task 化し、 57 | 58 | ```json 59 | { 60 | "version": "2.0.0", 61 | "tasks": [ 62 | { 63 | "label": "webpack build (watch)", 64 | "command": ["${workspaceFolder}/node_modules/.bin/webpack"], 65 | "args": [ 66 | "-w", 67 | "./src/frontend/morimoto_index.ts", 68 | "--output", 69 | "./public/html/js/morimoto_index.js" 70 | ], 71 | "type": "shell", 72 | "problemMatcher": ["$tsc"], 73 | "isBackground": true, 74 | "runOptions": { 75 | "runOn": "folderOpen" 76 | } 77 | } 78 | ] 79 | } 80 | ``` 81 | 82 | `"runOptions"."runOn": "folderOpen"`を設定すると、ワークスペースを開いた時に自動で実行させることができます。 83 | 84 | ## デバッグ実行 85 | 86 | 前の節で構成した server を起動し、`http://localhost:8080/morimoto_index.html`にアクセスすると、フロントエンドを含んだページを表示できます。 87 | 88 | リモート開発機能では、`Forward a Port`コマンドでサーバで起動したポートをローカルにつなぐことができ、手元の Web ブラウザで起動して確認することができます。 89 | 90 | Debugger For Chrome の拡張機能を使うことで、Chrome ブラウザを通してフロントエンドをデバッグすることができます。 91 | リモート開発機能と Debugger For Chrome の組み合わせでは、ポートフォワードした後にデバッグを開始すると、フロントエンドのコードをデバッグできます。 92 | 93 | まず、Chrome の Developer Tools を開くと、Chrome はファイルをどのように認識しているか確認することができます。 94 | 95 | ![](browser_bind.png) 96 | 97 | webpack://./src/frontend/morimoto_index.ts というパスが見て取れると思います。 98 | 99 | VSCode で Chrome をデバッグするには、この sourceMapPathOverrides というパラメータで、Chrome のパスと、VSCode のパスの対応を作ります。 100 | 101 | ```json 102 | { 103 | "version": "0.2.0", 104 | "configurations": [ 105 | { 106 | "type": "chrome", 107 | "request": "launch", 108 | "name": "morimoto Launch Chrome", 109 | "url": "http://localhost:8080", 110 | "webRoot": "${workspaceFolder}/public/html", 111 | "preLaunchTask": "morimoto webpack build", 112 | "sourceMapPathOverrides": { 113 | "webpack:///./src/*": "${workspaceRoot}/src/*" 114 | }, 115 | "sourceMaps": true 116 | } 117 | ] 118 | } 119 | ``` 120 | 121 | 次に、**Chrome の Dev Tools を閉じて下さい(開いたままでは VSCode であタッチできない制約があります)**。 122 | 123 | 課題 6 タスクの Done ボタンを押した時の、API へのアクセスの動作を[src/frontend/api/morimoto_task.ts#L29](../src/frontend/api/morimoto_task.ts#L29)に実装してみて下さい。 124 | 125 | 課題 7 上記のコード中にブレイクポイントを置き、デバッグ実行してみて下さい。 126 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | - [1. Live Share](./1.liveshare.md) 2 | - [2. ロジックの実装と、ユニットテストの実装とデバッグ](./2.unittest.md) 3 | - [3. サーバ API の実装](./3.server.md) 4 | - [4. フロントエンドの実装とデバッグ](./4.frontend.md) 5 | -------------------------------------------------------------------------------- /docs/application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/application.png -------------------------------------------------------------------------------- /docs/browser_bind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/browser_bind.png -------------------------------------------------------------------------------- /docs/code_comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/code_comment.png -------------------------------------------------------------------------------- /docs/comment_thread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/comment_thread.png -------------------------------------------------------------------------------- /docs/focus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/focus.png -------------------------------------------------------------------------------- /docs/follow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/follow.png -------------------------------------------------------------------------------- /docs/following_pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/following_pin.png -------------------------------------------------------------------------------- /docs/frontend_webapi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/frontend_webapi.png -------------------------------------------------------------------------------- /docs/functions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/functions.png -------------------------------------------------------------------------------- /docs/interface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/interface.png -------------------------------------------------------------------------------- /docs/share_server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/docs/share_server.png -------------------------------------------------------------------------------- /out/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/74th/vscode-typescript-handson/00a7797c6db895752a799f3dd72ba07c02deec03/out/.gitkeep -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo-list", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": {}, 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/74th/vscode-book-typescript.git" 10 | }, 11 | "author": "74th", 12 | "license": "MIT", 13 | "bugs": { 14 | "url": "https://github.com/74th/vscode-book-typescript/issues" 15 | }, 16 | "homepage": "https://github.com/74th/vscode-book-typescript#readme", 17 | "dependencies": { 18 | "@types/body-parser": "^1.19.0", 19 | "@types/express": "^4.17.6", 20 | "@types/mocha": "^5.2.7", 21 | "body-parser": "^1.19.0", 22 | "express": "^4.17.1", 23 | "mocha": "^10.1.0", 24 | "prettier": "^2.0.5", 25 | "source-map-loader": "^0.2.4", 26 | "ts-loader": "^5.4.5", 27 | "ts-node": "^8.9.1", 28 | "tslint": "^5.20.1", 29 | "typescript": "^3.8.3", 30 | "vue": "^2.6.11", 31 | "vue-class-component": "^7.2.3", 32 | "vue-property-decorator": "^8.4.2", 33 | "webpack": "^4.43.0", 34 | "webpack-cli": "^3.3.11" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /public/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TODO Sample 5 | 11 | 12 | 13 | 14 | 15 |
16 |

TODO Sample

17 | 18 |
19 |
20 |
21 | 28 |
29 | 36 |
37 |
38 |
39 |
40 | 41 |
42 |
43 |
49 |
50 |
51 |

{{ task.text }}

52 | Done 53 |
54 |
55 |
56 |
57 |
58 |
59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /public/html/js/.gitignore: -------------------------------------------------------------------------------- 1 | *index.js* 2 | -------------------------------------------------------------------------------- /src/frontend/api/task.ts: -------------------------------------------------------------------------------- 1 | import { ITask } from "../../model/task/task"; 2 | 3 | /** 4 | * フロントエンドにおいて、APIへのアクセスを担うモジュール 5 | */ 6 | 7 | export async function loadTasks(): Promise { 8 | const url = "/api/tasks"; 9 | const res = await fetch(url, { method: "GET" }); 10 | return await res.json(); 11 | } 12 | 13 | export async function postTask(task: ITask): Promise { 14 | const url = "/api/tasks"; 15 | const res = await fetch(url, { 16 | method: "POST", 17 | body: JSON.stringify(task), 18 | headers: { 19 | "Content-Type": "application/json", 20 | }, 21 | }); 22 | return await res.json(); 23 | } 24 | 25 | /** 26 | * タスクの完了をリクエストする 27 | */ 28 | export async function postTaskDone(task: ITask): Promise { 29 | // TODO: urlを作成する /api/tasks//done 30 | const url = "/api/TODO:"; 31 | await fetch(url, { 32 | method: "POST", 33 | headers: { 34 | "Content-Type": "application/json", 35 | }, 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /src/frontend/index.ts: -------------------------------------------------------------------------------- 1 | import { TaskListView } from "./views/taskList"; 2 | import { NewTaskView } from "./views/newTask"; 3 | 4 | /** 5 | * フロントエンドのルート 6 | * Vue.jsのモジュールを初期化する 7 | */ 8 | window.addEventListener("load", () => { 9 | 10 | const taskListView = new TaskListView({ 11 | el: "#taskListView", 12 | }); 13 | const newTaskView = new NewTaskView({ 14 | el: "#newTaskView", 15 | }); 16 | 17 | newTaskView.$on("updateTaskList", () => { 18 | taskListView.loadTasks(); 19 | }); 20 | 21 | taskListView.loadTasks(); 22 | }); 23 | -------------------------------------------------------------------------------- /src/frontend/views/newTask.ts: -------------------------------------------------------------------------------- 1 | import { Component, Vue } from "vue-property-decorator"; 2 | import { ITask } from "../../model/task/task"; 3 | import { postTask } from "../api/task"; 4 | 5 | /** 6 | * タスク追加ボタン 7 | */ 8 | @Component 9 | export class NewTaskView extends Vue { 10 | 11 | private text: string = ""; 12 | 13 | public async clickAddButton(): Promise { 14 | const task: ITask = { id: 0, text: this.text }; 15 | await postTask(task); 16 | this.text = ""; 17 | this.$emit("updateTaskList"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/frontend/views/taskList.ts: -------------------------------------------------------------------------------- 1 | import { Component, Vue } from "vue-property-decorator"; 2 | import { ITask } from "../../model/task/task"; 3 | import { loadTasks, postTaskDone } from "../api/task"; 4 | 5 | /** 6 | * タスクの一覧と、個々のタスク 7 | */ 8 | @Component 9 | export class TaskListView extends Vue { 10 | 11 | private tasks: ITask[] = []; 12 | 13 | public async loadTasks(): Promise { 14 | const tasks = await loadTasks(); 15 | this.tasks = tasks; 16 | } 17 | 18 | public async clickDone(task: ITask): Promise { 19 | await postTaskDone(task); 20 | await this.loadTasks(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/model/task/repository.ts: -------------------------------------------------------------------------------- 1 | import { ITask } from "./task"; 2 | 3 | /** 4 | * タスクを格納するリポジトリ 5 | */ 6 | export class Repository { 7 | private tasks: ITask[]; 8 | 9 | constructor() { 10 | // 初期タスク 11 | this.tasks = [ 12 | { 13 | id: 3, 14 | text: "task1", 15 | done: false, 16 | }, 17 | { 18 | id: 2, 19 | text: "task2", 20 | done: false, 21 | }, 22 | ]; 23 | } 24 | 25 | /** 26 | * タスクを追加する 27 | * @param task 追加するタスク 28 | * @returns 採番されたタスクID 29 | */ 30 | public AddTask(task: ITask): number { 31 | if (task.done === undefined) { 32 | task.done = false; 33 | } 34 | task.id = this.tasks[this.tasks.length - 1].id + 1; 35 | this.tasks.push(task); 36 | return task.id; 37 | } 38 | 39 | /** 40 | * タスクの一覧を取得する 41 | * @returns タスクリスト 42 | */ 43 | public ListTasks(): ITask[] { 44 | return this.tasks.filter((task) => !task.done); 45 | } 46 | 47 | /** 48 | * タスクを完了にする 49 | * @param id 完了にするタスクID 50 | */ 51 | public DoneTask(id: number) { 52 | 53 | this.tasks.forEach((task) => { 54 | 55 | // TODO: idが一致するタスクを検索して、タスクのdoneをtureに設定する 56 | 57 | }); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/model/task/task.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * タスク 3 | */ 4 | export interface ITask { 5 | id: number; 6 | text: string; 7 | done?: boolean; 8 | } 9 | -------------------------------------------------------------------------------- /src/server/api.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import bodyParser from "body-parser"; 3 | import { Repository } from "../model/task/repository"; 4 | import { ITask } from "../model/task/task"; 5 | 6 | /** 7 | * APIの設定 8 | */ 9 | export interface IConfig { 10 | // リスンするホストとポート 11 | ListenHost: string; 12 | // フロントエンドのファイルのディレクトリ 13 | WebRoot: string; 14 | } 15 | 16 | /** 17 | * API 18 | */ 19 | export class API { 20 | private app: express.Express; 21 | private repository: Repository; 22 | private conf: IConfig; 23 | 24 | constructor(conf: IConfig) { 25 | // タスクリポジトリを持つ 26 | this.repository = new Repository(); 27 | // Expressのインスタンスを作成する 28 | this.app = express(); 29 | // 設定 30 | this.conf = conf; 31 | // ルーティングの設定 32 | this.routing(); 33 | } 34 | 35 | /** 36 | * サーバーの起動 37 | */ 38 | public Run = () => { 39 | this.app.listen(this.conf.ListenHost); 40 | }; 41 | 42 | /** 43 | * Expressのルーティングの設定 44 | */ 45 | private routing() { 46 | this.app.use(bodyParser.json()); 47 | this.app.use(bodyParser.urlencoded({ extended: true })); 48 | 49 | // GETの場合タスクのリストを返す 50 | this.app.get("/api/tasks", this.list); 51 | // POSTの場合タスクを登録する 52 | this.app.post("/api/tasks", this.create); 53 | // タスクの完了 54 | this.app.post("/api/tasks/:id/done", this.done); 55 | 56 | // フロントエンドのHTMLを提供する 57 | this.app.use("/", express.static(this.conf.WebRoot)); 58 | } 59 | 60 | /** 61 | * タスクの一覧 62 | */ 63 | private list = (req: express.Request, res: express.Response) => { 64 | const tasks = this.repository.ListTasks(); 65 | res.json(tasks); 66 | }; 67 | 68 | /** 69 | * タスクの追加 70 | */ 71 | private create = (req: express.Request, res: express.Response) => { 72 | const task: ITask = req.body; 73 | const id = this.repository.AddTask(task); 74 | res.json({ id }); 75 | }; 76 | 77 | /** 78 | * タスクの完了 79 | */ 80 | private done = (req: express.Request, res: express.Response) => { 81 | const id = parseInt(req.params.id, 10); 82 | 83 | // TODO: idのタスクを完了にする 84 | 85 | res.json({}) 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /src/server/main.ts: -------------------------------------------------------------------------------- 1 | import * as api from "./api"; 2 | import * as process from "process" 3 | 4 | var port = "8080"; 5 | if (process.env.PORT) { 6 | port = process.env.PORT 7 | } 8 | 9 | const conf: api.IConfig = { 10 | WebRoot: "./public/html", 11 | ListenHost: port, 12 | }; 13 | 14 | const server = new api.API(conf); 15 | server.Run(); 16 | -------------------------------------------------------------------------------- /tests/model/task/repository_test.ts: -------------------------------------------------------------------------------- 1 | import { ITask } from "src/model/task/task"; 2 | import { describe, Suite, it } from "mocha"; 3 | import { Repository } from "src/model/task/repository"; 4 | import * as assert from "assert"; 5 | 6 | describe("Task repository", () => { 7 | 8 | it("初期化されたときには、2レコード含まれていること", () => { 9 | // タスクリポジトリ 10 | const repo = new Repository(); 11 | 12 | // リポジトリからタスクを取得 13 | const tasks = repo.ListTasks(); 14 | 15 | // 初期化された時は2レコード含まれている 16 | assert.equal(tasks.length, 2); 17 | }); 18 | 19 | it("1タスク追加できること", () => { 20 | // タスクリポジトリ 21 | const repo = new Repository(); 22 | 23 | // 新しいタスク 24 | const newTasks: ITask = { 25 | id: 0, 26 | text: "new task", 27 | }; 28 | // 新しいタスクを登録する 29 | repo.AddTask(newTasks); 30 | 31 | // タスクのリストを取得すると、 32 | // 追加したタスクが含まれていること 33 | const tasks = repo.ListTasks(); 34 | assert.equal(tasks.length, 3); 35 | assert.notEqual(tasks.find((task: ITask): boolean => { 36 | return task.text === "new task"; 37 | }), undefined); 38 | }); 39 | 40 | it("タスクを完了にでき、完了にしたタスクはリストから見えなくなっていること", () => { 41 | // タスクリポジトリ 42 | const repo = new Repository(); 43 | 44 | // 完了にするタスクを取得 45 | let tasks = repo.ListTasks(); 46 | const firstTask = tasks[0]; 47 | 48 | // TODO: タスクを完了にする 49 | 50 | // TODO: タスクが完了になって、見えなくなっていること 51 | tasks = repo.ListTasks(); 52 | assert.equal(tasks.length, 1) 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // npmモジュールを使う 4 | "module": "commonjs", 5 | 6 | // npmモジュールもimport文で読み込めるようにする 7 | "esModuleInterop": true, 8 | 9 | // 出力するJavaScriptのバージョン 10 | // 'ES3', 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT' 11 | "target": "ES2017", 12 | 13 | // JavaScriptの出力フォルダ 14 | "outDir": "./out", 15 | 16 | // TypeScriptの絶対参照時に使えるフォルダ 17 | // src/とtests/の2つのフォルダーを参照できるように、 18 | // ワークスペースルートを指定する 19 | "baseUrl": "./", 20 | 21 | // ソースマップ を出力する 22 | "sourceMap": true, 23 | 24 | // すべての箇所で型定義を強制する 25 | "strict": true, 26 | 27 | // vue.js でデコレータを使う 28 | "experimentalDecorators": true 29 | }, 30 | "exclude": ["tmp", "users"] 31 | } 32 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "object-literal-sort-keys": false, 9 | "ordered-imports": false 10 | }, 11 | "rulesDirectory": [] 12 | } 13 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | let exclude = [path.resolve(__dirname, "public")]; 4 | 5 | module.exports = { 6 | // entry: "./src/frontend/index.ts", 7 | mode: "development", 8 | devtool: "source-map", 9 | resolve: { 10 | extensions: [".ts", ".js"], 11 | alias: { 12 | vue$: "vue/dist/vue.esm.js", 13 | }, 14 | }, 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.ts$/, 19 | loader: "ts-loader", 20 | exclude, 21 | }, 22 | { 23 | enforce: "pre", 24 | test: /\.js$/, 25 | loader: "source-map-loader", 26 | exclude, 27 | }, 28 | ], 29 | }, 30 | devServer: { 31 | contentBase: "public/html/", 32 | }, 33 | // output: { 34 | // filename: "index.js", 35 | // path: path.resolve(__dirname, "./public/html/js") 36 | // } 37 | }; 38 | --------------------------------------------------------------------------------