Help us understand the problem. What is going on with this article?

Visual StudioでASP.NET Core + Vue.js + TypeScriptの環境構築してみた

追記(2018.12.26)

特にこだわりがないのであればVisual StudioでVue.jsの環境を整えるメリットはないです。
.vueファイルもうまく読み込まないですし。
vuejs/vue-clinuxt/create-nuxt-appで環境構築して、Vue.js部分はVisual Studio Codeで開発するのがベストだと思います。一押しはNuxt.jsBuefyです。楽ちんです。

仮に頑張ってWebpackの設定をおこなったとして、
その人がプロジェクトから離れてしまって誰も構成部分をさわれない。でもpackageのバージョンは上がっていく…脆弱性が…などの属人化も未然に防げますね!

はじめに

次のプロジェクトで.Net FrameworkにVue.jsを組み込むらしく、環境構築周りを調べました。
ASP.NET CoreとVue.jsの環境構築の手順を残します。
ちなみにCoreを使用したのは私の趣味です。

ソースコード

GitHubで公開しています。
https://github.com/ishiyama0530/TsVueTemplate

使わなかったもの

BabelはTypeScriptコンパイラがこなしてくれるので使ってません。
また、Gulpも必要ないだろうと思い使いませんでした。

[意訳]私がGulpとGruntを手放した理由

Visual Studioの設定(外部Webツール)

Visual StudioからどのNode.jsを使うかっていう設定。グローバルにインストールされているNode.jsを指定したいので「$(PATH)」を一番上しておきます。

1.png

構成

プロジェクト構成

10.png

今回はwebpackでTypeScriptのコンパイルを行うので、Visual StudioによるTypeScriptのコンパイルは不要です。無効にしておきましょう。

TsVueTemplate.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <TypeScriptCompileBlocked>True</TypeScriptCompileBlocked> //←これを追加
  </PropertyGroup>

  <ItemGroup>
    <Folder Include="wwwroot\" />
    <Folder Include="wwwroot\js\" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.6" />
    <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.0.3" />
  </ItemGroup>

  <ItemGroup>
    <None Update="ClientApp\vue.d.js">
      <DependentUpon>vue.d.ts</DependentUpon>
    </None>
    <None Update="ClientApp\vue.d.js.map">
      <DependentUpon>vue.d.js</DependentUpon>
    </None>
  </ItemGroup>

</Project>

package.json

TypeScriptとwebpackもグローバルにインストールしたくないのでpackage.jsonで管理します。最近のnpmはnpxコマンドでnode_modules内を直接実行できるので便利。

package.json
{
  "name": "tsvuetemplate",
  "version": "1.0.0",
  "devDependencies": {
    "css-loader": "^0.28.11", //webpackでCSSファイル間の依存関係の解決
    "style-loader": "^0.21.0", //webpackでstyleタグの生成
    "vue-loader": "~14.2.2", //webpackでvueをコンパイル
    "ts-loader": "^4.2.0", //webpackでtypescriptをコンパイル
    "typescript": "^2.8.3",
    "uglifyjs-webpack-plugin": "^1.2.5", //webpackでminifyをするため
    "vue-template-compiler": "^2.5.16", //vueのコンパイルに必要っぽい
    "webpack": "^4.6.0",
    "webpack-cli": "^2.1.2", //最新のwebpackではwebpack-cliが含まれなくなったらしく、これも入れないと怒られる
    "mkdirp": "^0.5.1", //windowsでmkdirpコマンドを使用するため
    "rimraf": "^2.6.2" //windowsでrimrafコマンドを使用するため
  },
  "dependencies": {
    "vue": "^2.5.16",
    "vue-class-component": "^6.2.0", //vueをクラス形式で記述したかったため
    "vue-property-decorator": "^6.0.0" //vueをクラス形式で記述するときに使う
  },
  "scripts": {
    "clean": "rimraf ./wwwroot/js", //webpackの出力フォルダを削除
    "build": "webpack -d", //webpackを開発モードでビルド
    "watch": "webpack --watch -d" //webpackのwatchを開発モードで実行
  },
  "-vs-binding": {
    "AfterBuild": [
      "build" //visualstudioのビルドにフック
    ],
    "Clean": [
      "clean" //visualstudioのクリーンにフック
    ],
    "ProjectOpened": [
      "watch" //visualstudioのプロジェクトオープン時にフック
    ]
  }
}

NPM task Runnerを入れるとvs-bindingはGUIから設定ででます。
2.png

tsconfig.json

tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "sourceMap": true,
    "strict": false, //strictをtrueにするのはまだ早そう
    "experimentalDecorators": true, //Decoratorを使うため
    "emitDecoratorMetadata": true, //Decoratorを使うため
    "module": "es2015",
    "moduleResolution": "node",
    "lib": [ "es5", "es2015.promise", "dom", "scripthost" ] // async/awaitを使うための
  },
  "include": [
    "./ClientApp/**/*.ts"
  ]
}

ソリューション内でtsconfigが見つかればプロジェクトファイルのTypeScriptのビルド設定は無効になります。
3.png

webpack.config.js

webpack.config.js
const path = require('path');
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

module.exports = (env, argv) => {
    const config = {
        entry: { 'index': './ClientApp/index.ts' },
        output: {
            path: path.resolve(__dirname, 'wwwroot/js'), //bundleファイルの出力先
            filename: '[name].bundle.js' //[name]はentryの'index'と対応(index.bundle.js)
        },
        module: {
            rules: [
                {
                    test: /\.vue$/, //vueファイル
                    loader: 'vue-loader',
                    options: {
                        loaders: {
                            'scss': 'vue-style-loader!css-loader!sass-loader',
                            'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
                        }
                    }
                },
                {
                    test: /\.ts$/, //tsファイル
                    loader: 'ts-loader',
                    exclude: /node_modules/,
                    options: {
                        appendTsSuffixTo: [/\.vue$/]
                    }
                },
                {
                    test: /\.css$/, //cssファイル
                    use: [
                        { loader: "style-loader" },
                        { loader: "css-loader" }
                    ]
                }
            ]
        },
        resolve: {
            extensions: ['.ts', '.js', '.vue', '.json'],
            alias: {
                'vue$': 'vue/dist/vue.esm.js' //vue$
            }
        }
    };

    if (argv.mode !== 'production') {
        config.devtool = '#eval-source-map'; //これがchromeでtsのデバッグするのに良さそう
    }

    if (argv.mode === 'production') {
        // minifyする
        config.optimization = {
            minimizer: [
                new UglifyJSPlugin({
                    uglifyOptions: {
                        compress: {
                            drop_console: true
                        }
                    }
                })
            ]
        };
    }

    return config;
};

webpackは'npx webpack -d'でdevelopment、'npx webpack -p'でproductionモードでコンパイルされます。

vueの型定義

tsconfigのincludeのPathに以下のファイルを用意してvueファイルを認識させます。

vue.d.ts
declare module "*.vue" {
    import Vue from "vue";
    export default Vue;
}

vue周り

Hello.vue
<script src="./Hello.vue.ts" lang="ts"></script>
<style src="./Hello.vue.css"></style>

<template>
    <section class="section">
        <div class="container">
            <h1 class="title">
                {{exampleProperty}}
            </h1>
        </div>
    </section>
</template>
Hello.vue.ts
import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'

@Component
export default class App extends Vue {
    @Prop({ default: 'Hello Ts Vue Template.' })
    exampleProperty: string
}
Hello.vue.css
h1 {
    color: orange !important;
}
index.ts
import Vue from 'vue'
import Hello from './Hello.vue'

new Vue({
    el: '#app-root',
    render: h => h(Hello)
})

index.cshtml

index.cshtmlはこんな感じです。
CSS書きたくないのでbulmaを使用しています。

index.cshtml
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Hello Bulma!</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css">
    <script defer src="https://use.fontawesome.com/releases/v5.0.7/js/all.js"></script>
</head>
<body>
    <div id="app-root">loading</div>

    <script src="~/js/index.bundle.js"></script>

    @*https://cdnjs.com/libraries/bulma*@
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css">

    @*https://fontawesome.com/*@
    <script defer src="https://use.fontawesome.com/releases/v5.0.7/js/all.js"></script>
</body>
</html>

いざ実行!

npm インストール後、Visual Studioの実行ボタン(IIS Express)からローカルサーバーを起動します。
5.png

Visual Studioのビルドにフックされたnpmのbuildスクリプトが実行されwwwroot/js配下にindex.bundle.jsが作成されました。

画面はこんな感じ。
6.png

フォントカラーを変更してみます。

Hello.vue.css
h1 {
    color: red !important;
}

7.png

Visual Studioのプロジェクト読み込み時にフックされているnpmのwatchスクリプトが実行されていれば、自動でコンパイルかけてくれるのでサーバー再起動の必要はないです。
変更が反映されない場合はwatchが動いていないのでVisual Studioの再起動か、タスクランナーエクスプローラーからwatchを起動させてください。

8.png

Chromeのブレイクポイントも止まります。

課題

Visual StudioからASP.NET Core + Vue.js + TypeScriptで実行することができました。
個人的にはSFC(single-file components)なら1つのvueファイルにtsもstyleも書きたいのですが、Visual Studioのエディターがまだ対応していないので、それぞれを別ファイルに分け、パスを読み込むことに。
また、対応するvueファイルとtsファイルのウィンドウを同時に開いている場合プロジェクトの指定が「その他」になってしまい、うまくファイルが読み込まれません。

9.png

感想

今までVisual Studio様に頼ってきてこの手のツールはほとんど使用したことがありませんでした。なのでかなり手探り状態の状態です。もっとよい方法などがあったらぜひ教えてください!

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away