title: How to use Alpine.data() in @push within Laravel Blade components?
body: <p>With Alpine.js 2 it was possible to develop Blade components with the following structure:</p>
  <pre><code>...
  &lt;div x-data=&quot;myApp()&quot;&gt;
  ...
  @once
      @push('child-scripts')
  &lt;script&gt;
      function myApp() {
          return {
              ...
          }
      }
  &lt;/script&gt;
      @endpush
  @endonce
  </code></pre>
  <p>This was great in that it allowed all the code for the component to be defined together.</p>
  <p>In Alpine.js 3 this approach of defining functions is deprecated (<a href="https://alpinejs.dev/upgrade-guide#alpine-data-instead-of-global-functions" rel="nofollow noreferrer">https://alpinejs.dev/upgrade-guide#alpine-data-instead-of-global-functions</a>). Instead, they should be defined like this:</p>
  <pre><code>...
  &lt;div x-data=&quot;myApp&quot;&gt;
  ...
  &lt;script&gt;
      document.addEventListener('alpine:init', () =&gt; {
          Alpine.data('myApp', () =&gt; ({
              ...
          }))
      })
  &lt;/script&gt;
  </code></pre>
  <p>However, it states &quot;you need to define <code>Alpine.data()</code> extensions BEFORE you call <code>Alpine.start()</code>&quot;. This suggests that with the new approach it is impossible (or at best unreliable) to use @push to add data functions for use in Blade components and, therefore, impossible to keep all the code for a Blade component together.</p>
  <p>My code all works fine with Alipne 3, if I use the deprecated approach. If I try to include the new syntax data function via @push, I get &quot;myApp is not defined&quot; JS error from my Blade component.</p>
  <p>I am using Alpine.js 3.9 installed as an NPM module. I have also tried using Alpine.js 3 via <code>&lt;script src=&quot;https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js&quot; defer&gt;&lt;/script&gt;</code>. The result is the same in both cases.</p>
  <p>Is there a way to keep all the code together in the Blade component?</p>
  <p><strong>UPDATE 25.02.2022</strong></p>
  <p>It seems I need to provide more details of what I am doing so here they are.</p>
  <p>The relevant bits of my app.blade.php are:</p>
  <pre><code>&lt;head&gt;
      ...
      &lt;script src=&quot;{{ asset('js/app.js') }}&quot; defer&gt;&lt;/script&gt;
      @livewireStyles
      ...
  &lt;/head&gt;
  &lt;body&gt;
      // HTML/Blade stuff here
      @livewireScripts
      @stack('child-scripts')
  &lt;/body&gt;
  </code></pre>
  <p>My app.js is like:</p>
  <pre><code>import Alpine from 'alpinejs'
  require('./bootstrap');
  window.Alpine = Alpine
  Alpine.start();
  </code></pre>
  <p>I have also tried:</p>
  <pre><code>require('./bootstrap');
  import Alpine from 'alpinejs'
  window.Alpine = Alpine
  Alpine.start();
  </code></pre>
  <p>My Blade component is like this:</p>
  <pre><code>...
  &lt;div x-data=&quot;myApp&quot;&gt;
  ...
  @once
      @push('child-scripts')
  &lt;script&gt;
      document.addEventListener('alpine:init', () =&gt; {
          Alpine.data('myApp', () =&gt; ({
              ...
          }))
      })
  &lt;/script&gt;
      @endpush
  @endonce
  </code></pre>
  <p><strong>When I access a page that uses the Blade component, I get &quot;Uncaught ReferenceError: myApp is not defined&quot;.</strong></p>
  <p>If I revert my Blade component to the old syntax (as follows) it works with no errors:</p>
  <pre><code>...
  &lt;div x-data=&quot;myApp()&quot;&gt;
  ...
  @once
      @push('child-scripts')
  &lt;script&gt;
      function myApp() {
          return {
              ...
          }
      }
  &lt;/script&gt;
      @endpush
  @endonce
  </code></pre>
  <p>The only difference between the working and failing versions is the way in which myApp is defined. The deprecated method works but, with the new method, it doesn't.</p>