Laravel MixでCodeMirror5→6にアップデートする

# 環境

* Laravel 8.x
* Laravel Mix v6
* Codemirror v5 → v6にアップデート
* npm 11.x

## コメント

* codemirror6から resources/sass/app.scss の追記は不要になりました。
* codemirror6ではtextareaに適用できなくなった(codemirror6はdiv適用)ため、codemirror5互換function editorFromTextArea() を追加して対応しました。

# Laravel Mix設定

## npmコマンド(ライブラリインストール)

```shell
# codemirrorのアンインストール
npm uninstall codemirror

# codemirror(v6)と表示言語(js, php, css, java)のインストール
npm i --save-dev codemirror @codemirror/lang-javascript @codemirror/lang-php @codemirror/lang-css @codemirror/lang-java

# ライブラリの最新化
npm update

# app.js, app.cssの最新化
npm run prod
```

## Laravel Mix設定

↓特に変更なし
```webpack.mix.js
const mix = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/js/app.js', 'public/js').vue()
    .sass('resources/sass/app.scss', 'public/css');

if (mix.inProduction()) {
    mix.version();
}
```

### codemirror v6設定

```resources/js/bootstrap.js
// --- codemirror 6
import { EditorView, placeholder } from "@codemirror/view";
window.EditorView = EditorView;
window.placeholder = placeholder;   // プレースホルダー有効化
import { basicSetup } from "codemirror"
window.basicSetup = basicSetup;
// 言語モード
// ※ 対応言語はgithubのcodemirrorでlang-xxxを確認 https://github.com/codemirror?q=lang-&type=all&language=&sort=
import {javascript} from "@codemirror/lang-javascript"
window.javascript = javascript;
import {css} from "@codemirror/lang-css"
window.css = css;
import {java} from "@codemirror/lang-java"
window.java = java;
import {php} from "@codemirror/lang-php"
window.php = php;
```

## npmコマンド(app.js, app.cssの最新化)

```shell
# app.js, app.cssの最新化
npm run prod
```

# 画面

```html
<head>
    <!-- Styles -->
    <link href="{{ url('/') }}{{ mix('css/app.css') }}" rel="stylesheet">
    <!-- Scripts -->
    <script src="{{ url('/') }}{{ mix('/js/app.js') }}"></script>
</head>

<textarea name="js" id="js" class="form-control" rows=20></textarea>
@include('plugins.common.codemirror', ['element_id' => 'js', 'mode' => 'javascript()', 'height' => '500px'])
```

```html:resources/views/plugins/common/codemirror.blade.php
@php
    // CodeMirrorの設定
    $element_id = $element_id ?? null;
    $mode = $mode ?? 'javascript()';
    $height = $height ?? '300px';
@endphp

<style>
    .cm-editor {
        border: 1px solid #ced4da;
        border-radius: 0.25rem;
        height: {{$height}};
    }
</style>
<script type="text/javascript">
    let view_{{$element_id}} = editorFromTextArea(document.getElementById("{{$element_id}}"))
    /**
     * codemirror 5 互換 function
     * @see https://codemirror.net/docs/migration/#codemirror.fromtextarea よりコピー
     */
    function editorFromTextArea(textarea) {
        let view = new EditorView({
            doc: textarea.value,
            extensions: [
                basicSetup,
                placeholder(textarea.placeholder),  // プレースホルダ
                EditorView.lineWrapping,            // 行を折り返す
                {{$mode}},                          // 言語モード
            ],
        })
        textarea.parentNode.insertBefore(view.dom, textarea)
        textarea.style.display = "none"
        if (textarea.form) textarea.form.addEventListener("submit", () => {
            textarea.value = view.state.doc.toString()
        })
        return view
    }
</script>
```

## 画面イメージ(JavaScript)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109904/74e8dca8-f9fe-402e-af68-3ce11d2fc1d1.png)

# 参考

* CodeMirror 5 to 6 Migration Guide
https://codemirror.net/docs/migration/
* codemirror5互換function editorFromTextArea()
  * https://codemirror.net/docs/migration/#codemirror.fromtextarea
* CodeMirror 6 Demo
  * https://codemirror.net/try/
* 行を折り返すオプション。EditorView.lineWrapping
  * How to use line wrapping in CodeMirror 6 - v6 - discuss.CodeMirror
https://discuss.codemirror.net/t/how-to-use-line-wrapping-in-codemirror-6/4924
    * > Your style is probably being overridden by the built-in styles. Try including in your set of extensions.EditorView.lineWrapping
* codemirror - javascript [ともやん・どっと・ねっと]
https://www.tomoyan.net/javascript/codemirror

# 所感

laravel mixでCodeMirror6の導入方法の記事がパッと見、見当たらなかったため、記事化しました。