0
0

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 を使わずに PHP で Vue の SFC (単一ファイルコンポーネント) みたいなことを実現する

Last updated at Posted at 2023-05-13

webpack を使わずに SFC が使いたい! webpack を導入するのは怖いし影響範囲が分からない!

こういう場合に、PHP の include と JavaScript の innerHTML を使って SFC のように書き換えてみます。ポイントとしては以下の2箇所になります。

<?php include "components/my-component.php" ?>

import ... from "..."; の代わりに PHP の include や blade の @include などを使い、コンポーネントが記述された別の PHP ファイルを読み込みます。

components/my-component.php
const MyComponent = {
    template: document.querySelector('#my-component-template').innerHTML,
    ...
}

また、 document.querySelector(...).innerHTML を使って生の HTML からテンプレートを取得することで、テンプレートにシンタックスハイライトが有効になるようにしています。

具体例

例えば以下のような PHP ファイルがあったとします。

image.png

index.php
<html>

<head>
    <title>PHP + Vue Demo</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>

<body>
    <div id="app">
        <h1>PHP + Vue Demo</h1>
        <my-component my-fruit="Apple"></my-component>
        <my-component my-fruit="Orange"></my-component>
        <my-component my-fruit="Strawberry"></my-component>
    </div>

    <style>
        h1 {
            color: #FF9900;
        }

        .fancy-border {
            border: red 3px solid;
        }
    </style>

    <script>
        const MyComponent = {
            props: ['myFruit'],
            data() {
                return {
                    myText: '300 yen',
                }
            },
            template: `
                <div>
                    <input type='text' v-model="myText" />
                    <p class='fancy-border'>
                        The price of {{myFruit}} is {{myText}}.
                    </p>
                </div>
            `
        };

        const {
            createApp
        } = Vue

        createApp({
            components: {
                'my-component': MyComponent,
            }
        }).mount('#app')
    </script>
</body>

</html>

問題点

まず問題点として、1つのファイルにコンポーネントが複数あり、1ファイルが長くなってしまうというものが挙げられます。これは PHP の include や blade の @include などを使って対処できます。
また、template が文字列となっていてシンタックスハイライトが使えないという問題に関しては、生の HTML にテンプレートを書いておき、 document.querySelector(...).innerHTML で取得することで解決します。SFC と同じように template タグ を使用できますが、<div style='display:none'> のように書いても問題ありません。

(なお、Vue では template: ... の代わりに el: '#app' のように書くことも出来ますが、この場合はコンポーネントを複数個マウントすることができないので今回は使用できません。)

上記を踏まえてコードを書き換えると以下のようになります。

components/my-component.php
<template id="my-component-template">
    <div>
        <input type='text' v-model="myText" />
        <p class='fancy-border'>
            The price of {{myFruit}} is {{myText}}.
        </p>
    </div>
</template>

<style>
    .fancy-border {
        border: red 3px solid;
    }
</style>

<script>
    const MyComponent = {
        props: ['myFruit'],
        template: document.querySelector('#my-component-template').innerHTML,
        data() {
            return {
                myText: '300 yen',
            }
        },
    };
</script>
index.php
<html>

<head>
    <title>PHP + Vue Demo</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>

<body>
    <?php include "components/my-component.php" ?>

    <div id="app">
        <h1>PHP + Vue Demo</h1>
        <my-component my-fruit="Apple"></my-component>
        <my-component my-fruit="Orange"></my-component>
        <my-component my-fruit="Strawberry"></my-component>
    </div>

    <style>
        h1 {
            color: #FF9900;
        }
    </style>

    <script>
        const {
            createApp
        } = Vue

        createApp({
            components: {
                'my-component': MyComponent,
            }
        }).mount('#app')
    </script>
</body>

</html>

おまけ:CodeSandbox のデモ

今回使ったファイルです。

CodeSandbox デモ

おわりに

この方法の欠点を挙げると多すぎて書ききれなくなってしまうのでここには書きません。なるべく可能なら .vue ファイルを使える環境を構築した方がいいと思います。

0
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?