laravel / vite-plugin

Laravel plugin for Vite.
MIT License
804 stars 152 forks source link

Link to UMD module inside node_modules #297

Closed mrleblanc101 closed 5 months ago

mrleblanc101 commented 5 months ago

Vite Plugin Version

1.0.2

Laravel Version

10.48.8

Node Version

20.12.2

NPM Version

10.5.0

Operating System

macOS

OS Version

14.5.0

Web browser and version

Version 124.0.6367.203 (Official Build) (arm64)

Running in Sail?

No

Description

I trying to add vanilla-cookieconsent to my website.

The goal is to:

  1. Import vanilla-cookieconsent
  2. Set the default consent state inside resources/js/default-consent.js
  3. Init GTM

Test 1:

Import vanilla-cookieconsent as an ESM module inside app.js, which is imported inside app.blade.php using the default @vite(['resources/js/app.js']).

This will not work because Vite will import it as a <script type="module"> which is executed after DOMContentLoaded which will run after our GTM init.

Test 2:

Link the file using <script src="{{ Vite::asset("node_modules/vanilla-cookieconsent/dist/cookieconsent.umd.js") }}"></script> after adding it inside input of vite.config.js:

laravel({
    input: [
        'resources/js/app.js',
        'resources/js/cookie-consent.js',
        'node_modules/vanilla-cookieconsent/dist/cookieconsent.umd.js',
    ],
    ssr: ['resources/js/ssr.js', 'resources/js/app.js'],
    refresh: true,
}),

In dev mode, everything works. In build mode, I get Unable to locate file in Vite manifest: node_modules/vanilla-cookieconsent/dist/cookieconsent.umd.js. Looking at the Vite manifest, I see the file is renamed cookieconsent.umd.js?commonjs-entry.

Test 3:

Try using <script src="{{ Vite::asset("node_modules/vanilla-cookieconsent/dist/cookieconsent.umd.js?commonjs-entry") }}"></script>, it somewhat works, but Vite will wrap this code so that CookieConsent is not available in the global scope (window.CookieConsent) which I need to switch the locale using window.CookieConsent.setLanguage(val) inside my Invertia-vue app.

Test 4:

Import the ESM version inside resources/js/cookie-consent.js which is a regular script (not type module), and add it to the global scope manually like so:

import * as CookieConsent from 'vanilla-cookieconsent';
window.CookieConsent = CookieConsent;

But I get this error: Uncaught SyntaxError: Cannot use import statement outside a module

Test 5:

My current solution is to link the CDN version, but I'd rather use the version installed by NPM as it allows me to manage the version easily using npm update.

Steps To Reproduce

<script src="https://cdn.jsdelivr.net/gh/orestbida/cookieconsent@3.0.1/dist/cookieconsent.umd.js"></script>
<!-- <script src="{{ Vite::asset("node_modules/vanilla-cookieconsent/dist/cookieconsent.umd.js") }}"></script> -->
<script src="{{ Vite::asset("resources/js/cookie-consent.js") }}"></script>

<!-- Scripts -->
@routes
@vite(['resources/js/app.js', "resources/js/Pages/{$page['component']}.vue"])

<!-- inertiaHead -->
@inertiaHead

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-XXXXXXXX');</script>
<!-- End Google Tag Manager -->
mrleblanc101 commented 5 months ago

So, if I return to the ESM import. This will work, as it will inline the ESM module

<script>
    {!! Vite::content('resources/js/cookie-consent.js') !!}
</script>

But this won't work and will give Uncaught SyntaxError: Cannot use import statement outside a module, as it will rely on the browser native ESM support, but it can't work since there is no type="module" on the script 😮

<script src="{{ Vite::asset("resources/js/cookie-consent.js") }}"></script>

Is there no way to tell vite to copy the content inside the file, instead of relying on the browser native ESM resolution ?

driesvints commented 5 months ago

Hi there,

Thanks for reporting but it looks like this is a question which can be asked on a support channel. Please only use this issue tracker for reporting bugs with the library itself. If you have a question on how to use functionality provided by this repo you can try one of the following channels:

However, this issue will not be locked and everyone is still free to discuss solutions to your problem!

Thanks.

mrleblanc101 commented 5 months ago

@driesvints I asked on the discord multiple times and never got an answer.

driesvints commented 5 months ago

@mrleblanc101 I'm very sorry but we just can't provide support for third party packages like vanilla-cookieconsent. Please try asking on their issue tracker.

mrleblanc101 commented 5 months ago

@driesvints The issue is not with vanilla-cookieconsent, the issue is that I can't link to an UMD. Vite will always use <script type="module">

driesvints commented 5 months ago

Can you provide a very simple repro repository without a third party library?

laravel new bug-report --github="--public"
mrleblanc101 commented 3 months ago

@driesvints Sorry for the long delay. Here is the repo: https://github.com/mrleblanc101/vite-umd-bug

I left comment, you'll need to uncomment each test case one by one and refer to the original message: https://github.com/laravel/vite-plugin/issues/297#issue-2301370080

You might also need to uncomment the proper file inside vite.config.js

jessarcher commented 3 months ago

Can you verify whether this is caused by something in this plugin or something with Vite itself?

This plugin mostly just configures a few Vite settings to work with Laravel (i.e. https://vitejs.dev/guide/backend-integration.html).

Does the same issue happen with a vanilla Vite project?

Have you tried using something like https://www.npmjs.com/package/vite-plugin-static-copy to copy the dist version of the package to your public directory and then link to it directly (I.e. not using the Vite facade)?

mrleblanc101 commented 3 months ago

I don't know much about Vite. I wouldn't know the equivalent of : <script src="{{ Vite::asset("resources/js/test4.js") }}"></script> or <script>{!! Vite::content('resources/js/test4.js') !!}</script>

No, I have seen vite-plugin-static-copy while looking into this issue, but I found it a very odd way to solve the issue. Copying a node_module into Laravel public folder seems rather odd to me...

In the end, inlining the script using <script>{!! Vite::content('resources/js/test4.js') !!}</script> wordked and did not require a third party vite plugin.