[Laravel9]Markdownエディタ”EasyMDE”を使ってみた with Tailwind CSS

  • 公開日:2022/7/19
この記事は最終更新日から2年以上が経過しています。

Laravel 9 でマークダウンエディタのEadyMDEを使ってみました。

環境

  • Laravel 9
  • Vite
  • Laravel Breeze
  • Tailwind CSS

Tailwind CSS Typographyをインストール

マークダウンエディタを導入した場合、フロントやプレビューでは記述内容をHTML形式で取得して表示することになりますが、Tailwind CSSはブラウザの標準スタイルをリセットしてしまうので、tailwind CSS Typographyというプラグインをマークダウンエディタ導入前にインストールしておきます。

$ npm install -D @tailwindcss/typography

tailwind.config.jsに以下を記述し、プラグインを追加します。

const defaultTheme = require('tailwindcss/defaultTheme');

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: [
        './vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
        './storage/framework/views/*.php',
        './resources/views/**/*.blade.php',
    ],

    theme: {
        extend: {
            fontFamily: {
                sans: ['Nunito', ...defaultTheme.fontFamily.sans],
            },
        },
    },

    plugins: [require('@tailwindcss/forms'), require('@tailwindcss/typography')],
};

そして、run vite

$ npm run dev

マークダウンエディタをインストール

いよいよマークダウンエディタをインストールします。

$ composer require graham-campbell/markdown:^14.0

vendor assets を公開します。
どのprovider または tag のファイルか聞かれるので、とりあえず”全て”と答えました。

$ php artisan vendor:publish
Which provider or tag's files would you like to publish?:
  [0 ] Publish files from all providers and tags listed below
  [1 ] Provider: GrahamCampbell\Markdown\MarkdownServiceProvider
  [2 ] Provider: Illuminate\Foundation\Providers\FoundationServiceProvider
  [3 ] Provider: Illuminate\Mail\MailServiceProvider
  [4 ] Provider: Illuminate\Notifications\NotificationServiceProvider
  [5 ] Provider: Illuminate\Pagination\PaginationServiceProvider
  [6 ] Provider: Laravel\Sail\SailServiceProvider
  [7 ] Provider: Laravel\Sanctum\SanctumServiceProvider
  [8 ] Provider: Laravel\Tinker\TinkerServiceProvider
  [9 ] Provider: Spatie\LaravelIgnition\IgnitionServiceProvider
  [10] Tag: flare-config
  [11] Tag: ignition-config
  [12] Tag: laravel-errors
  [13] Tag: laravel-mail
  [14] Tag: laravel-notifications
  [15] Tag: laravel-pagination
  [16] Tag: sail
  [17] Tag: sail-bin
  [18] Tag: sail-docker
  [19] Tag: sanctum-config
  [20] Tag: sanctum-migrations
 > 0

Copied Directory [/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/views] To [/resources/views/errors]
Copied Directory [/vendor/laravel/framework/src/Illuminate/Notifications/resources/views] To [/resources/views/vendor/notifications]
Copied Directory [/vendor/laravel/framework/src/Illuminate/Pagination/resources/views] To [/resources/views/vendor/pagination]
Copied File [/vendor/graham-campbell/markdown/config/markdown.php] To [/config/markdown.php]
Copied Directory [/vendor/laravel/sanctum/database/migrations] To [/database/migrations]
Copied File [/vendor/spatie/laravel-ignition/config/ignition.php] To [/config/ignition.php]
Copied File [/vendor/spatie/laravel-ignition/config/flare.php] To [/config/flare.php]
Copied Directory [/vendor/laravel/framework/src/Illuminate/Mail/resources/views] To [/resources/views/vendor/mail]
Copied Directory [/vendor/laravel/sail/runtimes] To [/docker]
Copied File [/vendor/laravel/sail/bin/sail] To [/sail]
Copied File [/vendor/laravel/tinker/config/tinker.php] To [/config/tinker.php]
Publishing complete.

ControllerとViewsファイルを編集

以下の構成とします。

├ app/
    ├ Http/
        ├ Controllers/
            └ BlogController.php
├ resources/
    ├ views/
        ├ layouts/
            └ app.blade.php
        ├ posts/
            ├ create.blade.php
        ├ article.blade.php

レイアウト用のapp.blade.php

head内に@stack(‘style’)、そして、bodyの閉じタグ直前に@stack(‘js’)を追記します。

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="csrf-token" content="{{ csrf_token() }}">

        <title>{{ config('app.name', 'Laravel') }}</title>

        <!-- Fonts -->
        <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">
        @stack('styles') 
        <!-- Scripts -->
        @vite(['resources/css/app.css', 'resources/js/app.js'])

    </head>

    <body class="font-sans antialiased">
        <div class="min-h-screen bg-gray-100">
            @include('layouts.navigation')

            <!-- Page Heading -->
            <header class="bg-white shadow">
                <div class="px-4 py-6 mx-auto max-w-7xl sm:px-6 lg:px-8">
                    {{ $header }}
                </div>
            </header>

            <!-- Page Content -->
            <main>
                {{ $slot }}
            </main>
        </div>
        @stack('scripts')
    </body>

</html>

投稿用のcreate.blade.phpにEasyMDEを追加

<x-app-layout>
    @push('styles')
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.css">
    @endpush
    <x-slot name="header">
        <h2 class="text-xl font-semibold leading-tight text-gray-800">
            {{ __('Post Create') }}
        </h2>
    </x-slot>

    <div class="py-12">
        <div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
            <div class="overflow-hidden bg-white shadow-sm sm:rounded-lg">
                <div class="p-6 bg-white border-b border-gray-200">
                    <form method="POST" action="{{ route('posts.store') }}">
                        @csrf
						// ・・・(省略)・・・
                        <div class="mb-6">
                            <label class="block">
                                <span class="text-gray-700">Description</span>
                                <textarea id="markdown-editor" class="block w-full mt-1 rounded-md" name="description" rows="3"></textarea>
                            </label>
                            @error('description')
                            <div class="text-sm text-red-600">{{ $message }}</div>
                            @enderror
                        </div>
						// ・・・(省略)・・・
                    </form>
                </div>
            </div>
        </div>
    </div>
    @push('scripts')
    <script src="https://cdn.jsdelivr.net/npm/easymde/dist/easymde.min.js"></script>
    <script>
        const easyMDE = new EasyMDE({
            showIcons: ['strikethrough', 'code', 'table', 'redo', 'heading', 'undo', 'heading-bigger', 'heading-smaller', 'heading-1', 'heading-2', 'heading-3', 'clean-block', 'horizontal-rule'], element: document.getElementById('markdown-editor')});
    </script>
    @endpush
</x-app-layout>

これで投稿画面のエディタが変わりました。
id名は任意。エディタに表示するアイコンもお好みに。

表示部分をコントロールするBlogContoller.php

DBにはマークダウン記法のまま保存し、表示のときにマークダウン記法をHTMLにします。

<?php

namespace App\Http\Controllers;

// ・・・(省略)・・・
use GrahamCampbell\Markdown\Facades\Markdown;

class BlogController extends Controller
{
    // ・・・(省略)・・・

    /*
     * 記事を表示
     */
    public function show( $slug ) {
        $article = Post::where('slug', $slug)->first();
        // マークダウンをhtmlに
        $article->body = Markdown::convert($article->body)->getContent();

        return view('article', ['article' => $article]);
    }
}

表示用のarticle.blade.php

<html>
    <head>
        // ・・・(省略)・・・
        @stack('styles')
        <!-- Scripts -->
        @vite(['resources/css/app.css', 'resources/js/app.js'])  
    </head>
    <body>
        // ・・・(省略)・・・
        <div class="prose lg:prose-xl">
            {!! $article->body !!}
        </div>
        // ・・・(省略)・・・
        @stack('scripts')
    </body>
</html>

最後にbuildしておく

$ npm run build