Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help with integration for Laravel Breeze Starter Kit #2

Closed
mandrasch opened this issue Jul 12, 2022 · 38 comments
Closed

Help with integration for Laravel Breeze Starter Kit #2

mandrasch opened this issue Jul 12, 2022 · 38 comments

Comments

@mandrasch
Copy link

mandrasch commented Jul 12, 2022

Hey,

thanks so much for providing this!

Laravel officially switched to their own vite-integration for their starter kits (See https://laravel.com/docs/9.x/vite, they are using https://www.npmjs.com/package/laravel-vite-plugin and their @vite-tag in blade).

I tried to use this plugin with the Laravel Breeze Starter Kit, but visiting https://ddev-laravel-breeze-vite.ddev.site:3001/@vite/client returns

502: Unresponsive/broken ddev back-end site.
This is the ddev-router container: The back-end webserver at the URL you specified is not responding. You may want to use "ddev restart" to restart the site.

Demo repo: https://github.com/mandrasch/ddev-laravel-breeze-vite
My installation commands: https://github.com/mandrasch/ddev-laravel-breeze-vite/blob/main/README.md#how-was-this-created

DDEV version: ddev version v1.19.3
OS: Mac OSX Big Sur 11.6.5, M1 chip

Is this an issue related to ddev-viteserve or a general DDEV issue?

Thanks very much in advance for any hints! 🙏

Best regards,
Matthias

image

image

image

@torenware
Copy link
Owner

torenware commented Jul 12, 2022

Looks like the problem is in your vite.config.js file:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css',
            'resources/js/app.js',
        ]),
    ],
    /* ADDED: */
    server: {
        https: true,
        hmr : {
            host: 'ddev-laravel-breeze-vite.ddev.site'
        },
        port: 3001
    },
});

The "ADDED" section should instead be:

    /* ADDED: */
    server: {
        port: 3000
    },

This is because the main point of ddev-viteserve is to let Vite operate behind DDEV's routers. Default settings for my add-on expect the vite server to put out http on port 3000. DDEV's router will handle wrapping the output in https and translating the port to 3001.

I'll likely update the docs soon to make this more clear; I'm also working on an extension to how the configuration works for DDEV generally with config.*.yaml files; once that fix lands, I'll take advantage of the new DDEV configuration feature to make my add-on more readily and intuitively configurable.

@mandrasch
Copy link
Author

Thanks very much for your fast reply! I tested some variations,

A)

server: {
        https: true,
        hmr : {
            host: 'ddev-laravel-breeze-vite.ddev.site'
        },
        port: 3000
    },

Opening https://ddev-laravel-breeze-vite.ddev.site/login returns: This site can’t provide a secure connectionddev-laravel-breeze-vite.ddev.site sent an invalid response. ERR_SSL_PROTOCOL_ERROR

B)

server: {
       /* https: true,*/
        hmr : {
            host: 'ddev-laravel-breeze-vite.ddev.site'
        },
        port: 3000
    },

Opening https://ddev-laravel-breeze-vite.ddev.site/login returns: Mixed Content: The page at 'https://ddev-laravel-breeze-vite.ddev.site/login' was loaded over HTTPS, but requested an insecure script 'http://ddev-laravel-breeze-vite.ddev.site:3000/@vite/client'. This request has been blocked; the content must be served over HTTPS.

But the good news:

C)

server: {
       /* https: true,*/
        hmr : {
            host: 'ddev-laravel-breeze-vite.ddev.site'
        },
        port: 3000
    },

and opening up http://ddev-laravel-breeze-vite.ddev.site/login without https:// works. 🥳

But... is there a way to make this work via https as well? 🤔

@torenware
Copy link
Owner

torenware commented Jul 12, 2022

Thanks very much for your fast reply! I tested some variations,

A)

server: {
        https: true,
        hmr : {
            host: 'ddev-laravel-breeze-vite.ddev.site'
        },
        port: 3000
    },

This one can't work, for two reasons.

  1. If you use https in the setting, the DDEV router won't be able to handle vite's output. It must have access to HTTP.
  2. The hmr.host setting is referring to a URL on your host, and not inside of the container, since inside of the container is all vite.config.js and the DDEV router have access to. In general, the hmr setting is unneeded, since server will do hmr automatically on any host/port that DDEV exports for you. These are by default 3000 for HTTP, and 3001 for HTTPS. HTTPS will use the same certificates that DDEV uses for HTTPS.

Opening https://ddev-laravel-breeze-vite.ddev.site/login returns: This site can’t provide a secure connectionddev-laravel-breeze-vite.ddev.site sent an invalid response. ERR_SSL_PROTOCOL_ERROR

True. The add-on exports HTTP on 3000, and HTTPS on 3001, as I said above.

B)

server: {
       /* https: true,*/
        hmr : {
            host: 'ddev-laravel-breeze-vite.ddev.site'
        },
        port: 3000
    },

Closer, but still not right: you don't want to hmr: {} block here, it's not what you want.

Opening https://ddev-laravel-breeze-vite.ddev.site/login returns: Mixed Content: The page at 'https://ddev-laravel-breeze-vite.ddev.site/login' was loaded over HTTPS, but requested an insecure script 'http://ddev-laravel-breeze-vite.ddev.site:3000/@vite/client'. This request has been blocked; the content must be served over HTTPS.

But the good news:

C)

server: {
       /* https: true,*/
        hmr : {
            host: 'ddev-laravel-breeze-vite.ddev.site'
        },
        port: 3000
    },

and opening up http://ddev-laravel-breeze-vite.ddev.site/login without https:// works. 🥳

But... is there a way to make this work via https as well? 🤔

Yep. Omit the hmr:{} block on your config, and you'll find you get the output you want on ddev-laravel-breeze-https://ddev-laravel-breeze-vite.ddev.site:3001

This really is all the settings you need:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css',
            'resources/js/app.js',
        ]),
    ],
});

since using the defaults here actually will server you HTTP on 3000 and HTTPS on 3001 with the correct certificates without you doing any additional configuration.

@torenware
Copy link
Owner

I've updated the README for release 0.1.1 to help make this more clear. I'm waiting on a new feature in DDEV to land before updating the README much more, since configuration will be a lot easier for people to do once I have access to config.*.yaml files that safely override config.yaml.

@mandrasch
Copy link
Author

mandrasch commented Jul 12, 2022

Hey, thanks again for your support! Your recommended setup

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css',
            'resources/js/app.js',
        ]),
    ],
});

results in the following generated HTML:

<script type="module" src="http://[::]:3000/@vite/client"></script><link rel="stylesheet" href="http://[::]:3000/resources/css/app.css" /><script type="module" src="http://[::]:3000/resources/js/app.js"></script>    </head>

Which results in:

image

Unfortunately I don't know all the details yet, but for me it seems to be the case that Laravels integration of vite depends on the {hmr:} setting for the @vite tag in blade.

Code references:

@mandrasch
Copy link
Author

mandrasch commented Jul 12, 2022

PS: Just found a tutorial for a similar use case (Local Valet Server) which uses hmr{} and also adds support for certificates https://freek.dev/2276-making-vite-and-valet-play-nice-together

@rfay
Copy link
Contributor

rfay commented Jul 12, 2022

You don't want to add certs, but rather have ddev-router be in charge of TLS termination in all cases.

@mandrasch
Copy link
Author

mandrasch commented Jul 12, 2022

Thanks @rfay, I'll withdraw certificates from this discussion for now! :-D

Further technical investigation:

The @vite tag just reads an URL string from the file public/hot. Source code

        if (is_file(public_path('/hot'))) {
            $url = rtrim(file_get_contents(public_path('/hot')));

            return new HtmlString(
                $entrypoints
                    ->map(fn ($entrypoint) => $this->makeTag("{$url}/{$entrypoint}"))
                    ->prepend($this->makeScriptTag("{$url}/@vite/client"))
                    ->join('')
            );
        }

The public/hot-file is generated while running ddev vite-serve start (or ddev exec npm run dev) by laravel-vite-plugin (npm). Without {hmr} setting, the public/hot-file is has just this content:

image

With hmr.host configured, there is the DDEV url in the public/hot-file.

Official docs for vites server.hmr: https://vitejs.dev/config/#server-hmr

If specifying server.hmr.server, Vite will process HMR connection requests through the provided server. If not in middleware mode, Vite will attempt to process HMR connection requests through the existing server. This can be helpful when using self-signed certificates or when you want to expose Vite over a network on a single port.

@mandrasch
Copy link
Author

Forgot to mention the most important thing ;-) The @vite tag is used in resources/views/layouts/app.blade.php which is the basic template of the Laravel Breeze Starter Kit:

        <!-- Scripts -->
        @vite(['resources/css/app.css', 'resources/js/app.js'])

And sorry in advance if I'm totally on the wrong track with hmr ;-)

@torenware
Copy link
Owner

torenware commented Jul 12, 2022

And sorry in advance if I'm totally on the wrong track with hmr ;-)

:-)

What does the blade tag

<!-- Scripts -->
        @vite(['resources/css/app.css', 'resources/js/app.js'])

resolve to in the actual HTML generated and passed to the browser?

It would need to either use the full path with the full URL using the host name used in DDEV generated certs, or a relative URI starting in "/", so that you inherit the correct protocol://HOST_NAME from the document. Anything else would be a problem.

I don't know the internals of the Laravel Vite integration. I've written an integration for Golang, which should work in a similar way; I just generate golang template functions that resolve to tags. I know that I use the relative URI approach. Not sure what the Larvel's integration does, but we should be able to accommodate whatever it does do.

@tyler36
Copy link
Contributor

tyler36 commented Jul 13, 2022

@vite(['resources/css/app.css', 'resources/js/app.js']) expands to ...

<script type="module" src="http://127.0.0.1:3000/@vite/client"></script>
<link
    rel="stylesheet"
    href="http://127.0.0.1:3000/resources/css/app.css"
>
<script
    type="module"
    src="http://127.0.0.1:3000/resources/js/app.js"
></script>
<link
    rel="icon"
    type="image/x-icon"
    href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAHZJREFUOE/t08ENgDAIBdD/6XjO4Jhup2CIMVXaao3xZq/AS4HAYZxmvHjcARGklqOKpRU7AaQUeaYKEGghFcAOCOEAhTCzKtINuFpDMkAkirdQ/iD2pZZncgvEYm/pARDLt5n8wPczuL6syy30HmV1jb3FMW8FYduDoVoaPbwAAAAASUVORK5CYII="
>

@torenware
Copy link
Owner

@tyler36 Where does Laravel Vite get its notion of what the src is for that script tag? How is it set?

Assuming that you're getting served HTTPS at MY-DDEV-SECURE-HOST:someport, we'd want src to be:

src="https://MY-DDEV-SECURE-HOST:3001

if we are using the add-on with its default settings. How would we get the Laravel integration to do that? Where is it getting the setting?

@mandrasch
Copy link
Author

mandrasch commented Jul 13, 2022

@tyler36 Where does Laravel Vite get its notion of what the src is for that script tag? How is it set?

See comment above, @vite (PHP) reads the URL string from public/hot-file (generated via nodejs in laravel-vite-plugin).

I quickly checked, that seems to be a laravel-vite-plugin feature and not a standard feature of vite. It reads from laravels .env file and gets the APP_URL. Also it uses config.server.host and config.server.hmr.host:

configureServer(server) {
            const hotFile = path.join(pluginConfig.publicDirectory, 'hot')

            const envDir = resolvedConfig.envDir || process.cwd()
            const appUrl = loadEnv('', envDir, 'APP_URL').APP_URL

            server.httpServer?.once('listening', () => {
                const address = server.httpServer?.address()

                const isAddressInfo = (x: string|AddressInfo|null|undefined): x is AddressInfo => typeof x === 'object'
                if (isAddressInfo(address)) {
                    viteDevServerUrl = resolveDevServerUrl(address, server.config)
                    fs.writeFileSync(hotFile, viteDevServerUrl)

                    setTimeout(() => {
                        server.config.logger.info(colors.red(`\n  Laravel ${laravelVersion()} `))
                        server.config.logger.info(`\n  > APP_URL: ` + colors.cyan(appUrl))
                    })
                }
            })

//...

/**
 * Resolve the dev server URL from the server address and configuration.
 */
function resolveDevServerUrl(address: AddressInfo, config: ResolvedConfig): DevServerUrl {
    const configHmrProtocol = typeof config.server.hmr === 'object' ? config.server.hmr.protocol : null
    const clientProtocol = configHmrProtocol ? (configHmrProtocol === 'wss' ? 'https' : 'http') : null
    const serverProtocol = config.server.https ? 'https' : 'http'
    const protocol = clientProtocol ?? serverProtocol

    const configHmrHost = typeof config.server.hmr === 'object' ? config.server.hmr.host : null
    const configHost = typeof config.server.host === 'string' ? config.server.host : null
    const serverAddress = address.family === 'IPv6' ? `[${address.address}]` : address.address
    const host = configHmrHost ?? configHost ?? serverAddress

    return `${protocol}://${host}:${address.port}`
}

https://github.com/laravel/vite-plugin/blob/85c69328af542c80b368f6f4c270067033911af3/src/index.ts#L159

@mandrasch
Copy link
Author

mandrasch commented Jul 13, 2022

But according to that, server.host should also work (without setting server.hmr.host) in vite.config.ts.

    server:{
        host: 'ddev-laravel-breeze-vite.ddev.site'
    }

But it returns http://[::]:3000 in public/hot. Maybe a bug in laravel-vite-plugin? 🤔

@mandrasch mandrasch changed the title Help with 502: Unresponsive/broken ddev back-end site (Laravel Breeze Starter Kit) Help with integration for Laravel Breeze Starter Kit Jul 13, 2022
@torenware
Copy link
Owner

How is Laravel Vite configured? I find it unlikely that it's getting settings out of vite.config.js, for the same reason I don't do it in golang: parsing that file is not something you want to do if you're not using nodejs. THERE HAS TO BE SOME OTHER PLACE LARAVEL VITE IS GETTING ITS SETTINGS. And those are the settings you need to change, NOT vite.config.js.

This is a good question for Enzo Innocenzi, but a quick look at the docs shows that there is indeed a place for these configurations. Short version: the dev-server configuration needs to tell Laravel Vite how to create the tags. I'm not sure exactly how vite.php is being used, so you'll need to explain that vite is running inside a docker container and that it is routed out to the host. Not sure exactly what the settings would be, but likely that is the place to get this configured.

@tyler36
Copy link
Contributor

tyler36 commented Jul 13, 2022

https://github.com/innocenzi/laravel-vite/blob/fa591aa02f20a0bec6d3b6e32c03ef438e4ceb06/docs/src/guide/essentials/development.md

Has some information about changing host, certificates and using with Lagoon, Laravel Sails

@mandrasch
Copy link
Author

mandrasch commented Jul 13, 2022

Whoops, I should have made this more clearer and do a better research before:

I'm trying to use the brand new core integration of vite in Laravel. This is not the third party plugin https://laravel-vite.dev/ by Enzo Innocenzi anymore.

It is instead in laravel/framework and laravel/vite-plugin by Laravel.

References:

@torenware
Copy link
Owner

Still, it's substantially based on Enzo's work. Looked at the docs for the official integration; this is in fact this case, also as Enzo explains it on the Vite dev discord.

I've left a long note explaining what we're trying to do for Enzo, asking who is best suited to answer the question. My sense is that Enzo may well be able to, since the official integration owes so much to his previous work.

@mandrasch
Copy link
Author

I've left a long note explaining what we're trying to do for Enzo, asking who is best suited to answer the question. My sense is that Enzo may well be able to, since the official integration owes so much to his previous work.

Thanks, very much appreciated! (Already learned a lot about Laravel & Vite as well here in this issue 👍 )

@torenware
Copy link
Owner

Here's what I hear from Enzo:

But I need Laravel Vite to generate the correct tags for the web page that Laravel renders to the browser

That would be configurable with dev_url - that's the URL with which tags are generated. But it's also used to configure some stuff in the Vite plugin, so there may be side-effect depending on what you use. I'd be willing to work out a solution if that's not sufficient though, I'll need to understand the problem better but we might PR something to have a different dev_url and URL for generated tags

@torenware
Copy link
Owner

So... if you guys will try out using dev_url in vite.php, and see if it (1) creates the right tag in the browser and (2) actually works, we'll see where this goes.

@mandrasch
Copy link
Author

Thanks very much for working on this together!

Maybe we should split our efforts at this point? 🤔

A) My goal is to use the official (new) vite implementation in laravel/framework + laravel-vite-plugin with DDEV.

Demo DDEV repository to play around: https://github.com/mandrasch/ddev-laravel-breeze-vite/

Enzo Innocenzi just confirmed in vite Discord that Laravels new implementation does not have a dev_url and no config/vite.php-file (currently).

But I guess the NodeJS source code of laravel-vite-plugin could be changed to read something like VITE_DEV_URL from .env I guess. I already posted the important source code as comment.

B) We could try to get innocenzi/laravel-vite working with DDEV and ddev-vite-serve.

@torenware
Copy link
Owner

I'm not that familiar with the Laravel project, so I don't know how easy / how hard it is to get feature changes. But I encourage you to file an issue on the Laravel project with your use case.

I did notice a feature where you can substitute your own code to render out the blade tag. This might be your best approach, since you'd be able to read DDEV environment variables w/o causing side effects.

@torenware
Copy link
Owner

Here's what I was thinking about. I'd try constructing the correct URL using the DDEV generated environment variables, largely ignoring whatever laravel is telling you :-)

@torenware
Copy link
Owner

BTW -- if you're happy with where we are, feel free to close this issue if Github lets you do that.

@mandrasch
Copy link
Author

mandrasch commented Jul 13, 2022

Thanks, also interesting approach! 👍

I just read in the Laravel Sail community (also a Docker tool), that they just overwrite public/hot file manually for testing (after first run of vite) Source. This is the easiest way of testing/debugging of course, could have figured this out myself. Sorry! 🤦 😆

I tried it with the following for public/hot

https://ddev-laravel-breeze-vite.ddev.site:3001

and a the vite.config.ts you suggested earlier:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css',
            'resources/js/app.js',
        ]),
    ]
});

It renders out the script tag correctly and the first run works:

<script type="module" src="https://ddev-laravel-breeze-vite.ddev.site:3001/@vite/client">

But the web socket tries to connect on 3000 instead of 3001:
image

Also tried the following config, unfortunately no success. But it feels close?! 🤔

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';

export default defineConfig({
    plugins: [
        laravel([
            'resources/css/app.css',
            'resources/js/app.js',
        ]),
    ],
    server:{
        hmr:{
            port: 3001
        }
    }
});

image

@torenware
Copy link
Owner

No, server.hmr is almost certainly wrong. A web socket will need to be routed out by the nginx router, inside of DDEV. So if you do that, the web socket will never get out of DDEV.

Remember, the settings of vite.config.ts are seen entirely inside of ddev, before routing occurs. Everything seen by the browser is outside of DDEV, after routing. But the Laravel app, since it runs inside of DDEV, can see DDEV_HOSTNAME and HTTPS_EXPOSE. On one of my test systems these have the values of:

DDEV_HOSTNAME=phpunit-course.ddev.site
HTTPS_EXPOSE=8843:80,8026:8025,3001:3000

The 3001:3000 portion of the latter is the configuration of the router; port 3000 inside the container (HTTP) is 3001 outside the container (HTTPS). This is why server.hmr will not work. I'll creating settings for the 3000 and 3001 defaults as soon as the config.*.yaml merger issue lands in DDEV HEAD.

So you want Laravel to generate the tags as "https://$DDEV_HOSTNAME:3001". If the official Laravel Vite does not give you a vite.php setting, you'll need to do this substitution in these calls, something like this:

// Overrides script tag generation
Vite::makeScriptTagsUsing(function (string $url, Chunk $chunk = null): string {
   if (isset($_ENV['DDEV_HOSTNAME']) {
     $url = sprintf('https://%s:3001', $_ENV['DDEV_HOSTNAME']);
  }
    return sprintf('<script type="module" src="%s" defer></script>', $url);
});

// Overrides style tag generation
Vite::makeStyleTagsUsing(function (string $url, Chunk $chunk = null): string {
   if (isset($_ENV['DDEV_HOSTNAME']) {
     $url = sprintf('https://%s:3001', $_ENV['DDEV_HOSTNAME']);
  }
    return sprintf('<link rel="stylesheet" href="%s" crossorigin="anonymous" />', $url);
});

calling them where the docs say you should. This will change your URLs w/o side effects, I think. Once I have a place to set the default values of vite-port-inside-ddev and vite-port-outside-ddev, you'd use those as well.

@mandrasch
Copy link
Author

Thanks for your help! Can't quite get my head around all this.

Good news (http):

When I use http://ddev-laravel-breeze-vite.ddev.site:3000 in public/hot and open the website via http://ddev-laravel-breeze-vite.ddev.site, ddev-vite-serve works fine. 👍 👍 👍


https:

I think I misunderstood that https:// isn't currently working out of the box with ddev-vite-serve?

I already achieved overwriting the @Vite tag via hot-file trick manually:

image

But now the error were within vites client.ts which tries to open a websocket to default port 3000:

image

image

Therefore I edited the hmr settings to change this, which seems to be the wrong approach as you pointed out.

I'll fiddle around with that and get a better understanding. If you find time in future (or someone else reading this), a HTTPS-demo repository would be really appreciated!

@mandrasch
Copy link
Author

Closing this to not show it as open in your repo, but happy to discuss it further in here. Thanks very much for taking the time!

@torenware
Copy link
Owner

http://ddev-laravel-breeze-vite.ddev.site:3000 works to serve HTTP (but not HTTPS, as you've seen) because DDEV's internal router renders port 3000 inside as 3000 outside as well.

The router also proxies out that internal 3000/HTTP out as 3001/HTTPS external.

@mandrasch
Copy link
Author

I'm unfortunately not deeply familiar with DDEV router. But DDEV docs state

This works only for services with an http API, but results in having both http and https ports (9998 and 9999)
https://ddev.readthedocs.io/en/stable/users/extend/custom-compose-files/#docker-composeyaml-examples

So is this a DDEV router issue? Would opening the site via https:// work with vite if we could expose port 3000 as HTTPS-only port (without caring about HTTP whatsoever)? 🤔

@torenware
Copy link
Owner

You potentially could; but you have to route HTTP to somewhere from what @rfay tells me, or the router won't work right. This is, um, a FEATURE of the router.

But you certainly could switch the HTTP and HTTPS ports if you wish; easy to do by changing the DDEV env variables HTTPS_EXPOSE and HTTP_EXPOSE (see config.yaml), making external HTTPS 3000, and external HTTP 3001, for example. But I'm going to wait to config update I've been working on with Randy.

@rfay
Copy link
Contributor

rfay commented Jul 13, 2022

This is all about what all reverse proxies do... all over the world. They typically route traffic from one entrypoint to a back-end HTTP server. And they often also terminate https.

Because https traffic is encrypted, the back-end servers can't be serving https, because the reverse proxy (ddev-router in this case) can't decrypt it. And even if it did, it would mean two separate encryption/decryption processes and two separate sets of keys. Quite a mess.

So ddev-router and every other reverse proxy in its class do https on the edge, and talk http typically to back-end servers. vite in this case is the back-end server.

I hope that helps understanding of what's going on here.

@mandrasch
Copy link
Author

mandrasch commented Jul 14, 2022

Thanks very much @rfay for clarification! (And sorry for the noob questions!)

So I guess this narrows it down to vite and use the reverse proxies + https?

I saw that they were quite a few issues submitted regarding reverse proxies (and docker) in vites official repo, I'll try to dive into them: https://github.com/vitejs/vite/issues?q=reverse+proxy+

Some mention server.hmr.clientPort which I haven't heard before. Maybe it's gotten easier with vite v3 as well. And on the bright side: The Laravel Sail Docker users face a similiar challenge I guess.

But for debugging this I think I'll have to take a step back and start with a blank vite instead of a Laravel Starterkit:

I'll try to get a working DDEV https setup with a blank vite v2 and blank vite v3 first. (I still don't have an idea what the correct vite config for https + docker + reverse proxy is).

If anyone has any working DDEV + vite + https example repository, please let me know 🙏

@mandrasch
Copy link
Author

mandrasch commented Jul 14, 2022

PS: Okay, Craft CMS devs to the rescue!

Just saw https://nystudio107.com/docs/vite/#local-development-environment-setup --> "Using DDEV" (via craftquest)

They use the following config, which worked for me in https 🥳🥳🥳
(with overriding public/hot manually to use https://ddev-laravel-breeze-vite.ddev.site:3000 and using ddev exec npm run dev)

The vite config is the following, just as @torenware suggested all the time here ;-) (And it's same as vite --host in https://github.com/torenware/ddev-viteserve/blob/master/commands/web/vite-serve#L30 as far as I understand it)

server: {
  host: '0.0.0.0',
  port: 3000
} 

The docker-compose file differs:

# Override the web container's standard HTTP_EXPOSE and HTTPS_EXPOSE services
# to expose port `3000` of DDEV's web container.
version: '3.6'
services:
  web:
    ports:
      - '3000'
    environment:
      - HTTP_EXPOSE=${DDEV_ROUTER_HTTP_PORT}:80,${DDEV_MAILHOG_PORT}:8025,3001:3000
      - HTTPS_EXPOSE=${DDEV_ROUTER_HTTPS_PORT}:80,${DDEV_MAILHOG_HTTPS_PORT}:8025,3000:3000

The downside of using ports: directly instead of expose: (with DDEV router) is mentioned in the DDEV docs:

That approach usually isn't sustainable because two projects might want to use the same port, so we expose the additional port (to the docker network) and then use the ddev-router to bind it to the host.
https://ddev.readthedocs.io/en/stable/users/extend/custom-compose-files/#docker-composeyaml-examples

Therefore the above approach can be used on only one DDEV project at a time, the second project will say "port already in use" (if I understand the docs correctly).

@rfay
Copy link
Contributor

rfay commented Jul 14, 2022

You just want expose, not ports if you're going to put it on port 3000, because with your current setup ddev-router is also going to try to use port 3000, so I don't think this one will even be able to come up.

I'll be happy to do a screenshare call with you and work with you on your project and explain what's going on here. Let me know if you'd like to and there's a convenient time.

But if you're going to use ports then remove 3000/3001 from HTTP_EXPOSE and HTTPS_EXPOSE. But then if you try to use https, and if vite is serving https, your browser won't trust it. DDEV has things set up to trust the mkcert CA.

@mandrasch
Copy link
Author

mandrasch commented Jul 14, 2022

Thanks so much for your offer, @rfay! But I do hope this won't be necessary anymore (and you can use your time in a better way. )

I just tried out another simple setup with vite3, a custom port 5133 and your suggested approach - it works! 🥳 🥳 🥳

(Hope I got it right this time. Funfact: ports also worked. But thanks for the details, I won't use ports of course! 😉 )

Repo: mandrasch/vite-php-setup-ddev-test (Fork of andrefelipe/vite-php-setup)

# ./ddev/docker-compose.vite.yaml
version: '3.6'
services:
  web:
    expose:
      - '5133'
    environment:
      - HTTP_EXPOSE=${DDEV_ROUTER_HTTP_PORT}:80,${DDEV_MAILHOG_PORT}:8025,5134:5133
      - HTTPS_EXPOSE=${DDEV_ROUTER_HTTPS_PORT}:80,${DDEV_MAILHOG_HTTPS_PORT}:8025,5133:5133
/* vite/vite.config.js */
  server: {
    // respond to all network requests
    host: '0.0.0.0',
    // "Set to true to exit if port is already in use, instead of automatically try the next available port."
    strictPort: true,
    port: 5133
  },

So using the vite port in HTTPS_EXPOSE instead of HTTP_EXPOSE did the trick for https-DDEV-sites.

If I switch it to the following - which is also used in https://github.com/torenware/ddev-viteserve/blob/b133b2dd70c4359190755625ebc8f4887d72a850/docker-compose.viteserve.yaml - I get the following error when I open my DDEV project with https (which is the DDEV default afaik?):

GET https://vite-php-setup-ddev-test.ddev.site:5133/main.js net::ERR_SSL_PROTOCOL_ERROR

    # not working for https://vite-php-setup-ddev-test.ddev.site
    expose:
      - '5133'
    environment:
      - HTTP_EXPOSE=${DDEV_ROUTER_HTTP_PORT}:80,${DDEV_MAILHOG_PORT}:8025,5133:5133
      - HTTPS_EXPOSE=${DDEV_ROUTER_HTTPS_PORT}:80,${DDEV_MAILHOG_HTTPS_PORT}:8025,5134:5133

Needs some more testing with Laravel, vite2, etc. - but I won't share that here anymore. 😉

Thanks so much you all! 🙏 🙏 🙏

@bmoex
Copy link

bmoex commented Oct 12, 2022

I got it working on a similar note but i used web_extra_exposed_ports and abusing the wss protocol (picked from https://github.com/laravel/vite-plugin/blob/main/src/index.ts#L393);

.ddev/config.yaml

web_extra_exposed_ports:
  - name: ViteJS
    container_port: 5173
    http_port: 5172
    https_port: 5173

vite.config.js

...
    server: {
        hmr: {
            protocol: 'wss',
            host: 'example.ddev.site',
        }
    },
...

and then run ddev exec npm run dev -- --host

I dont know if this will conflict any websocket flow but it works for my usecase and wanted to share :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants