0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

webpackを使わずにASP.NET(Razor pages) で TypeScript + jQuery を使う

Last updated at Posted at 2022-04-24

ASP.NET MVCでもTypeScriptを使ってコーディングをしたいと思いましたが、自分の思うような例がなかったためサンプルを作成しました。

※Visual Studio 2022で確認しています

要件

  1. 面倒な設定はできる限り行わない
    • ビルドスクリプト(gulp)やバンドラー(webpack)を利用せずに複数.jsファイルを利用する
  2. jQueryを利用可能とする
    • jQueryは<script>タグでは読み込まず、各jsファイルでimportして利用する。
  3. Visual Studioでプログラムを実行する際、F5キーのみで実行できる状態にする
    • gulpなどのタスクランナーも利用しない
  4. Pageとjs(ts)ファイルを1:1の関係にする。各ページで対応関係にあるスクリプトファイルのみを読み込むようにする。

実現方法

一言で言うと、TypeScriptのモジュール形式をAMDにして、ブラウザ側からRequireJSでロードすることで実現します。

要件1. 2. について

TypeScriptを利用する場合、ブラウザ側での依存解決のためトランスパイルしたjsファイルと依存モジュールを1ファイルにまとめるバンドル処理が必要になります。
しかしwebpackなどのバンドラーは設定が難しく、本質的なことを始める前に挫折する原因になるため今回は利用しません。

バンドラーを利用せずに別のJSファイル利用する方法として、下記の方法があります。

  1. ESModules 形式のモジュールをimportで利用
  2. AMDモジュールをRequireJS経由で利用

ESModule形式であれば、ブラウザ側でimportをするとサーバから必要なjsファイルを取得してくれるため、非常に簡単に処理することができます。ところが、jQueryがESModule形式をサポートしていないため、利用することができません。

幸いなことに、jQueryはAMDモジュールとして利用可能なため、RequireJSによる動的読み込み形式を利用することとします。

要件3. について

TypeScriptファイルを保存すると自動でjsファイルにコンパイルしてくれるツールMicrosoft.TypeScript.MSBuildを導入します。(保存先などトランスパイル時の設定は後で説明(tsconfig.json)します)

要件4. について

各ページ毎に作成した.tsファイルを@section scripts{~}で読み込みます。
tsファイル内でimport $ from 'jquery'とすれば、RequireJSが動的にロードしてくれるため、各ページでjqueryを読み込む必要はありません。

@section scripts {
 <script data-main="other.js" src="~/js/lib/require.js" asp-append-version="true"></script>
}
  • other.ts
import $ from 'jquery';
import { currentDate } from "testlib";

// タイマーで画面の時刻を更新
$(() => {
    $("#currentDate").text(currentDate());
    setInterval(() => {
        $("#currentDate").text(currentDate());
    }, 1000);
});

制限事項

  • npm でインストールするモジュールは基本的に利用不可
    • 読み込みがRequireJSに依存しているため、CommonJS形式のモジュールは利用不可です(AMDやUMD形式のモジュールは利用できます)

実装手順

最終的に下記のようなファイル構成になります。(トランスパイルされたtsファイルがjsフォルダに入ります)

img20.png

1. Razor pagesプロジェクトを作成する

新しいプロジェクトの作成からASP.NET Core Web アプリを選択します。

img21.png

2. TypeScript関連設定

  • TypeScriptを保存するフォルダ(scripts/js)を作成します。

scripts直下ではなく/jsの下にファイルを作成します。RequireJSでファイルをロードする際、/jsフォルダに入れておくと読み込みやすいためです(baseURLの制限)

  • tsconfig.tsonを追加します。
{
  "compileOnSave": true,
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "target": "ES2015",
    "module": "AMD",
    "outDir": "wwwroot/js",
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true
  },
  "include": ["scripts/**/*"]
}

特に重要な設定

項目 説明
module AMD形式で出力
outDir トランスパイルしたjsの保存先
allowSyntheticDefaultImports jQuery利用のために必要
esModuleInterop jQuery利用のために必要
  • Microsoft.TypeScript.MSBuildをインストール(.tsファイル保存時に自動でトランスパイル)

img10.png

  • NuGetパッケージマネージャを起動して、検索欄にMicrosoft.TypeScript.MSBuildを入力してインストールします。保存先などコンパイル時の設定はtsconfig.tsonに従います。

img11.png

jQueryのインストール

jQueryと型定義をインストールします。npmでpackage.jsonのひな形を作成(npm init)後、jQueryと型定義を追加します。

npm init -y
npm i jquery @types/jquery

jQueryのソースファイルをwwwroot/js/lib/にコピーする(フォルダは適宜作成してください)

jQueryのソースは下記フォルダに配置されています。
node_modules\jquery\dist\jquery.min.js

RequireJSの設定

site.jsファイル(全ページで共通に読み込まれる.jsファイル)でbaseUrlを設定します。jsファイルは/jsフォルダ配下から読み込みます。
未指定の場合、プロジェクトルート直下から.jsファイルを読み込もうとして404 not found(ファイルが見つからない)となります。

var require = {
    baseUrl: "js",
    paths: {
        'jquery': 'lib/jquery.min'
    }
};

動作確認用ページ、TypeScriptソース

indexページ

jQueryでボタンクリックイベントをバインドするサンプル。別.tsファイル(testlib.ts)からclass、interfaceを世読み込み、利用しています。

img30.png

  • index.ts
import $ from 'jquery';
import { Student, Person } from './testlib';

const greeter = (person: Person) => {
    return `Hello, ${person.firstName} ${person.lastName}`;
}

 const TSButton = () => {
    const firstname = $('#firstname').val() as string;
    const lastname = $('#lastname').val() as string;
    const user = new Student(firstname, lastname);
    $("#result").html(greeter(user))
}

// ボタンにclickイベントハンドラを設定
$('#btnClickMe').on('click', TSButton);

// グローバルスコープに公開(onclick="TSButton()" で利用できる)
window['TSButton'] = TSButton;
  • index.cshtml

@section scriptsでスクリプトファイルを読み込んでいます。

@page
@model IndexModel
@{
    ViewData["Title"] = "jQueryでクリックイベント付与";
}

@section scripts {
 <script data-main="index.js" src="~/js/lib/require.js" asp-append-version="true"></script>
}

<div class="text-center">

    <div class="my-2">
        <div class="input-group">
          <span class="input-group-text">First and last name</span>
          <input type="text" id="firstname" aria-label="First name" class="form-control" value="first" />
          <input type="text" id="lastname" aria-label="Last name" class="form-control" value="last" />
        </div>
        <div id="result"> </div>
    </div>


    <button id="btnClickMe" class="btn-primary btn-md" >
        $("#btnClickMe").on("click", TSButton);
    </button>

    <button class="btn-secondly btn-md" onclick="TSButton()" >
        onclick="TSButton()"
    </button>

    <div class="my-2">
        <a asp-page="./other">Otherページ</a>
    </div>
</div>

otherページ

ページを切り替えて、スクリプトが切り替わることを確認するサンプル。ページ読み込み時にタイマーで時刻を更新するスクリプトを実行しています。

img31.png

  • other.ts
import $ from 'jquery';
import { currentDate } from "testlib";

// タイマーで画面の時刻を更新
$(() => {
    $("#currentDate").text(currentDate());
    setInterval(() => {
        $("#currentDate").text(currentDate());
    }, 1000);
});
  • other.cshtml

@section scriptsでスクリプトファイルを読み込んでいます。

@page
@model RazorPagesWithTypeScript.Pages.OtherModel
@{
    ViewData["Title"] = "ページ毎に読み込むスクリプトを切り替え";
}

@section scripts {
 <script data-main="other.js" src="~/js/lib/require.js" asp-append-version="true"></script>
}
<div class="text-center">
    現在時刻:
    <span id="currentDate"/>
</div>

<div class="my-2">
    <a asp-page="index">Top(index)ページ </a>
</div>
  • Shared/_Layout.cshtml

共通ページ。@await RenderSectionAsyncの位置で、各ページの@section scriptsが出力されます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"]</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</head>
<body>
    <div class="container">
        <h4 class="display-8" >ASP.NET(Razor pages) + TypeScript + JQuery サンプル</h4>
        <div>(@ViewData["Title"])</div>
         @RenderBody()
    </div>

    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?