Markdownに書いたコードを直接実行するアプリの技術的要素


1. この記事について

この記事は、私が開発したExecNoteというアプリケーションの技術的要素を説明したものです。

ExecNoteは、Markdownに記述したコードを、ワンクリックで実行できるアプリケーションです。現在は、NodeJS、Python、Powershellのコード実行に対応しています。

https://execnote.app/

現在はWindowsのみですが、今後、Mac OSX、Linux、AWS Lambda等でコード実行できるSaaSアプリ化へ対応予定です。

2. 作者について

私は、SIerのSEとして5年、その後、自動車部品製造業社内SEとして6年ほどシステムエンジニアとして働いています。実務では主にERPや製造業務システムの要件定義・設計開発・保守を担当しています。VB6とCOBOLで開発されたERPのメンテナンスもしています。

ブログは主に技術的な内容を書いています。

Twitterでは、ExecNoteの宣伝や、感じたことを徒然と書いています。

3. ExecNoteの機能概要

ExecNoteは、2020年8月22日時点で、主に以下の機能を実装しています。

  1. Markdownドキュメントのツリー表示
  2. Markdown編集機能
  3. プレビュー機能
  4. オートセーブ機能
  5. コード実行機能
  6. コード実行時の作業ディレクトリ変更機能

画像のコピペに対応していなかったり、今一つ機能としては足りていないところもありますが、必要最低限の機能を実装しています。

機能概要は、以下のYouTube動画にまとめています。

https://youtu.be/b_WYr35MUSc

4. 使用したプログラム言語とフレームワーク

このアプリケーションは、ローカルPC上に .NET Core Blazor サーバーを起動して、ブラウザで表示しています。よって、バックグラウンドは、Blazor Server と C#, フロント側は、HTML, JavaScript, CSSを使用しています。

Markdownを編集するエディタは、Visual Studio Codeと同じく、Monaco Editor を採用しました。補完機能が充実していますし、個人的に好きなので。

https://microsoft.github.io/monaco-editor/

MarkdownをHTMLに変換するエンジンは、marked.js を採用しました。シンプルでものすごく使いやすいです。

https://github.com/markedjs/marked

Markdownドキュメントや設定情報は、内部にポータブルNoSQLデータベースを作成して保存しています。ポータブルNoSQLデータベースは、LiteDBを採用しました。
LiteDBは、.NET Framework で書かれています。動作も高速で、ファイルサイズも32KB程度とかなり軽量です。

https://www.litedb.org/

5. コマンドと言語の取得方法

ExecNoteは、Markdownに記述されたコードと言語を判断して、実行することが最重要機能要件です。

コード記入のMarkdown文法では、以下のようにプログラム言語を記述できます。

これをmarked.jsでHTMLに変換すると、<pre class="language-js"><code>...</code></pre>のように、classに言語名が付与されます。

これをもとにプログラム言語を判定します。そのため、Markdownの記述が誤っていると、誤ったインタプリタで実行されてしまいます。

コードは、<code>...</code>の中に書かれた内容をinnerTextで取得します。

これらの情報をBlazorServer側に渡して、コードを実行します。

6. フロントエンド(JavaScript)からBlazor Serverの関数を呼び出す方法

フロントエンド(JavaScript)からBlazor Server関数を呼び出すには、DotNet.invokeMethodAsyncを使用します。

以下のコードは、ExecNoteプロジェクトのJSInvokableExecCodeというBlazorServer側の関数を呼び出します。引数は、codeInfoJsonです。

DotNet.invokeMethodAsync('ExecNote', 'JSInvokableExecCode', codeInfoJson)

JSInvokableExecCodeから返り値がある場合、.thenを用いて取得します。

    DotNet.invokeMethodAsync('ExecNote', 'JSInvokableExecCode', codeInfoJson)
    .then(data => {

    })

詳しくは以下を参照ください。

https://usefuledge.com/js-call-blazor-function.html

7. Monaco Editor の使い方

まず、https://microsoft.github.io/monaco-editor/を参照し、npm installなどを使用してダウンロードします。

_Host.cshtmlloader.jsを記述します。

    <script src="~/monaco-editor/min/vs/loader.js"></script>

razorコンポーネント等に、Monaco Editor を表示するDIVタグを記述します。

<div id="EditorContainer"></div>

以下のような、初期化用のJavaScript関数を定義します。オプションは、PlaygroundもしくはAPI DOCSをみると分かるかもしれません。

https://microsoft.github.io/monaco-editor/playground.html

https://microsoft.github.io/monaco-editor/api/index.html 

Monaco Editor の OnChangeなイベントはwindow.editor.onDidChangeModelContentで実行できます。

function initializeMonaco()
{
    require(['vs/editor/editor.main'], function () {
        window.editor = monaco.editor.create(document.getElementById('EditorContainer'), {

            value: GetReadMe(),
            language: 'html',
            theme: "vs-dark"
        });

        window.editor.onDidChangeModelContent(() => {
            PreviewMarkdown();
            AutoSaveDB();
        });


}

8. 終わりに

機能を実装するにはいろいろな手法があると思いますが、1つの例として読んで頂ければと思います。

また、ExecNoteは、定常的に実行するコードをMarkdownと一緒に管理することで、作業効率が見込まれるアプリケーションです。

よければダウンロードをお願いします!

https://execnote.app/