Giter VIP home page Giter VIP logo

async-alpine's Introduction

Accudio website

GitHub Twitter Website Donate

Fourth incarnation of accudio.com. Content brought over from existing subrion-based system into a static site based on next.js and React.

Website for Alistair Shepherd at alistairshepherd.co.uk. Built by Accudio.

Version History

  • 0.1.0 - Initial functional version

Build setup

Built with next.js, for more info: next.js docs.

# install dependencies
$ npm install

# development server — hot reload at localhost:3000
$ npm run dev

# export static project
$ npm run export

async-alpine's People

Contributors

accudio avatar awcodes avatar helio3197 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

async-alpine's Issues

Look into using `x-ignore` instead of attribute renaming

This could massively simplify how we handle disabling/enabling Alpine, depending on how it handles x-ignore.

It could also unlock #11, if Alpine checks the live node for x-ignore rather than relying on the NodeList passed with the MutationEvent.

Allowing to inject components inside <template>

Hi. Here's the thing

I have two ways of displaying the same component (desktop and mobile), so my initial thought was:

<template x-if="isMobile">
      <div
        id="componentOne"
        ax-load="event"
        class="contents"
        x-data="componentOne()"
        x-html="view"
        x-ignore
      ></div>

      <div
        id="componentTwo"
        ax-load="event"
        class="contents"
        x-data="componentTwo()"
        x-html="view"
        x-ignore
      ></div>
</template>

But this willl result in loading just the "componentOne". Then I thought "one for each component", so:

<template x-if="isMobile">
      <div
        id="componentOne"
        ax-load="event"
        class="contents"
        x-data="componentOne()"
        x-html="view"
        x-ignore
      ></div>
</template>

<template x-if="isMobile">
      <div
        id="componentTwo"
        ax-load="event"
        class="contents"
        x-data="componentTwo()"
        x-html="view"
        x-ignore
      ></div>
</template>

Siblings s willl result in the same error shown on issue 39 previous to 1.2.2 when trying to inject the view.

Then I use the next 6 hours to figure it out and finally got it working by implementing a new strange format, looking like this:

<div id="someContentsContainer" class="contents" x-transition.in>
    <template
      x-if="isMobile"
      x-data="componentOne()"
      id="componentOne"
      ax-load="event"
      x-ignore
    >
      <div class="contents" x-html="view"></div>
    </template>

    <template
      x-if="isMobile"
      x-data="componentTwo()"
      id="componentTwo"
      ax-load="event"
      x-ignore
    >
      <div class="contents" x-html="view"></div>
    </template>
</div>

As you can see, I needed to create each component inside <template> instead of normal <div> tag and then add a new contents containers to inject the view, which is just a raw html imported as an Alpine's instance.

Maybe this is not a bug (oddly it works) and I think it's useful to have a guide on how to apply "layouting" logic with nested components. The other option I had was to replicate the "isMobile" logic in each component which would have been sad.

CORS Error

Hey there!

First of all thanks for this repo!
I tried it out but I always run into the same issue :

async-alpine.script.js:1 Uncaught (in promise) TypeError: Failed to resolve module specifier 'myComponent.js'. The base URL is about:blank because import() is called from a CORS-cross-origin script.

The myComponent.js file is in a public folder and uses your example code from the readme.

Is this happening because I am loading your script via cdn?

I am using the cdn-link from the readme.

And, btw, will there be a cdn link for the new beta?

0.4.0 rebuild using `x-ignore`, API changes and support for dynamic content

This is an issue to discuss and test the new 0.4.0 version of Async Alpine. The beta for the new version is on the 0.4-rebuild branch, with updated documentation in the README.

Install the new version from GitHub like so:

npm install -S accudio/async-alpine.git#0.4-rebuild

Changes

This version has significant breaking changes, be sure to review these before updating an existing project. Check out the updated README for more examples and information.

  • Feature: Adds support for dynamically-added content, including client-side routing;
  • Feature: Adds method to register components that handle their own downloads using .data('name', callback);
  • Breaking change: Requires x-ignore attribute on all components;
  • Breaking removal: Removes 'parent' strategy—now nested components can only initialise when their ancestors have;
  • Breaking change: API to initialise and start has changed to be more similar to Alpine;
  • Improvement: Significant size, speed and efficiency improvements;
  • Improvement: Re-architecture makes the project easier, more understandable and more extensible I believe;

I would appreciate if anyone was able to help me with testing this, I've significantly expanded the project test suite but it consists of small, contrived examples so I would be keen to get any real-world testing that is possible beyond my own.

In the build of this I've encountered some new additions I would like to make in #11 and #7, but I'd like to get this through the door and put those into 0.5 shortly after this release. I would also like to add documentation for using Async Alpine with different platforms and build tools but again getting this released is my priority.

Observer unable to listen on body.replaceWith()

I'm using flamethrower as a client-side router that uses .replaceWith() to update the whole document.body and the observer unable to catch it.

After further investigation, the .replaceWith() seems to create a new body instance resulting in the observer missing its targets to monitor, there's no log coming out after the body is replaced.

For now, I temporarily fix it by changing the observer target into documentElement and condition to watch the title & body changes when the entry target is head or HTML, then body children.

Vite build fails for module importing with AsyncAlpine.data()

Hi! I've been trying to build a project using AsyncAlpine + Vite for the last two days with no luck. I'm writing because I have no idea how to accomplish this.

This is my folder structure:

  • ./
    • main.js
    • index.html
    • assets
      • js
        • components
          • Home
            • home.js
          • Header
            • home.js
          • Footer
            • footer.js
        • utils
          • someFiles.js

This is my vite.config.js:

//import {VitePWA} from 'vite-plugin-pwa';
import {defineConfig} from 'vite';
import {compression} from 'vite-plugin-compression2';
import {splitVendorChunkPlugin} from 'vite';
import compress from 'compression';
import {VitePluginFonts} from 'vite-plugin-fonts';
import VitePluginBrowserSync from 'vite-plugin-browser-sync';
import PathEnv from 'vite-plugin-patch-env';
import mockData from 'vite-plugin-mock-data';
import VitePluginHtmlEnv from 'vite-plugin-html-env';
// Icons
import Icons from 'unplugin-icons/vite';
import IconsResolver from 'unplugin-icons/resolver';
import AutoImport from 'unplugin-auto-import/vite';

export default defineConfig({
  root: './',
  base: './',
  build: {
    emptyOutDir: true
  },
  publicDir: 'public',
  css: {
    preprocessorOptions: {
      scss: {
        includePaths: ['./assets/css']
      }
    }
  },
  plugins: [
    splitVendorChunkPlugin(),
    VitePluginFonts({
      google: {
        families: ['Josefin Sans']
      }
    }),
    VitePluginHtmlEnv({
      compiler: true
    }),
    mockData({
      mockAssetsDir: './mockAssets'
    }),
    PathEnv(),
    compression(),
    AutoImport({
      resolvers: [
        IconsResolver({
          prefix: false,
          extension: 'raw',
          enabledCollections: ['carbon', 'mdi']
        })
      ]
    }),
    Icons({
      autoInstall: true,
      compiler: 'raw',
      scale: 1.2, // Scale of icons against 1em
      defaultStyle: '', // Style apply to icons
      defaultClass: '' // Class names apply to icons
    }),
    VitePluginBrowserSync({
      bs: {
        reloadDelay: 500,
        notify: false,
        ghostMode: false
      }
    }) /*,
    VitePWA({
      registerType: 'autoUpdate',
      devOptions: {
        enabled: true
      }
    })*/
  ]
});

This is my main.js:

import './assets/css/main.scss';
import AsyncAlpine from 'async-alpine';
import Alpine from 'alpinejs';
import focus from '@alpinejs/focus';
import persist from '@alpinejs/persist';
import moment from '@victoryoalli/alpinejs-moment';
import timeout from '@victoryoalli/alpinejs-timeout';
import * as HashRouter from '@techexp/hash-router';
import {util} from 'prettier';

document.addEventListener('alpine:initialized', () => {
  console.log('Alpine Inited');
});

//window.Alpine = Alpine;
// Start Async Alpine
AsyncAlpine.init(Alpine)
  .data('homeModule', () => import('./assets/js/components/Home/home.js'))
  .data('toastModule', () => import('./assets/js/components/Toast/toast.js'))
  .data('shopInfo', () => import('./assets/js/components/ShopInfo/shopInfo.js'))
  .data('orderHeader', () => import('./assets/js/components/Operations/OrderHeader/orderHeader.js'))
  .data('orderTabs', () => import('./assets/js/components/Operations/OrderTabs/orderTabs.js'))
  .data('operationModule', () => import('./assets/js/components/Operations/operation.js'))
  .data('orderList', () => import('./assets/js/components/Operations/OrderList/order.js'))
  .data('orderGroup', () => import('./assets/js/components/Operations/OrderGroup/orderGroup.js'))
  .start();
// Start Alpine
Alpine.plugin(focus);
Alpine.plugin(persist);
Alpine.plugin(timeout);
Alpine.plugin(moment);
Alpine.start();

This is my index.html:

<!DOCTYPE html>
<html lang="en" data-theme="fika" class="overflow-y-hidden">
	<head>
		<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin/>
		<link rel="preload" as="style" onload="this.rel='stylesheet'" href="https://fonts.googleapis.com/css2?family=Josefin Sans&display=swap"/>
		<meta charset="UTF-8"/>
		<link rel="icon" type="image/x-icon" href="./assets/favicon.67af206a.ico"/>
		<meta name="viewport" content="width=device-width, initial-scale=1"/>
		<meta http-equiv="cache-control" content="no-cache"/>
		<meta http-equiv="expires" content="0"/>
		<meta http-equiv="pragma" content="no-cache"/>
		<title>FikaCore</title>
		<script type="module" crossorigin src="./assets/index.f178bb58.js"></script>
		<link rel="modulepreload" crossorigin href="./assets/vendor.88f6f930.js"/>
		<link rel="stylesheet" href="./assets/index.62293656.css"/>
	</head>
	<body>
		<div id="app" x-data>
			<div id="homeModule" ax-load x-data="homeModule()" x-html="view" x-ignore></div>
		</div>
	</body>
	<script>console.log('===== En modo DESARRROLLO =====');</script>
</html>

When I run vite build && vite preview I got:

Captura de pantalla -2023-02-16 18-48-19

And I think this problem is related to the dist structure:

Captura de pantalla -2023-02-16 18-50-01

Since every module is in assets/js/components the dist index.html couldn't find the module because it's not the same folder structure as dev mode. Any thoughts?

Regards

Allow setting custom prefix for Async Alpine

We support custom prefixes for Alpine, but the likelihood is if someone is using that it's because they want HTML validation.

In that case Async Alpine doesn't allow setting a custom prefix in order to pass validation.

We should change the API so you can declare a custom prefix for Alpine and for Async Alpine. Proposed:

AsyncAlpine(Alpine, {
  prefix: 'data-ax-',
  alpinePrefix: 'data-x-'
})

Child component init twice using inline strategy

Hi, I don't know if missing something but here's the scenario:

<!-- Home Section -->
<div x-transition ax-load ax-load-src="js/components/OrderModule/order.js" x-data="orderModule()" x-html="view" x-ignore></div>
import Order from './order.html?raw';

export default function orderModule() {
  return {
    welcome: 'Order Module Inited',
    view: Order,
    init() {
      console.log(this.welcome);
      this.$root.innerHTML = this.view;
    }
  };
};

The orderModule component loads perfectly. But then ...

<!-- Order Section -->
<div x-transition ax-load ax-load-src="js/components/ChildModule/child.js" x-data="childModule()" x-html="view" x-ignore></div>
import ChildOrder from './child.html?raw';

export default function childModule() {
  return {
    welcome: 'Child Order Module Inited',
    view: ChildOrder,
    init() {
      // Prints "Child Order Module Inited" twice
      console.log(this.welcome);
      this.$root.innerHTML = this.view;
    }
  };
};

The childModule init method runs twice. Maybe I'm missing something because if I move the childModule to HomeModule (where the OrderModule is) it will only run once.

If not missing anything then I think each module runs one time per child level (third-level nesting will run 3 times)

Does not support the `@click` interaction pattern

@ is not a valid character within a HTML attribute name, therefore when we try and rename ax-@click back to @click we get the below error.

Uncaught DOMException: Failed to execute 'setAttribute' on 'Element': 'ax-@click' is not a valid attribute name.

I can't think of any way around this and restore @click directly, but we could transform into the x-on: pattern in order to preserve functionality. For example:

<!-- source html -->
<div @resize.window="">

<!-- after Async Alpine inits and before component enabled -->
<div [email protected]="">
<!-- OR -->
<div ax-x-on:resize.window="">

<!-- after component initialisation -->
<div x-on:resize.window="">

Allow nesting of `ax-load` components

Nesting ax-load does not guarantee the order in which components load. This will likely make nested components that rely on each other inconsistent.

Race condition with nesting

Hello,

I'm experiencing a race condition issue with nested async alpine when processing mutations via the _mutations setup here. The problem surfaces when I try to reference a variable from the parent component in the child component.

Usually, the parent node is able to download the javascript and execute the x-data directive first. However, sometimes the child node executes first, leading to an error when attempting to access an unset variable. When I pause at the time of error with debugger and inspect the DOM, I notice that the child node has already had its x-ignore attribute removed, while the parent node still has its x-ignore attribute. If I continue with debugger, I can see that parent node then gets its x-ignore removed and x-data processed after.

I suspect that issue may be caused by _componentStrategy being async but not waited on, and so it can't guarantee that the parent node downloads the javascript and activates itself before its child components. Normally, x-ignore on any parent node should prevent any alpine directives from running in any child node, but because async alpine runs Alpine.initTree directly on the child node, it appears to ignore this.

Quick example of a setup, and let's imagine that component2.js references a variable that is set up in component1.js, such as this.component1property.

<div
    x-ignore
    ax-load
    ax-load-src="/assets/component1.js"
    x-data="component1"
>
     <div
        x-ignore
        ax-load
        ax-load-src="/assets/component2.js"
        x-data="component2"
    >
        ...
    </div>
</div>

I do see some historical implementation of some parent strategy that appears to deal with similar concerns, but looks like that has long been removed. Any thoughts?

Cannot reference "$wire" outside a Livewire component

Laravel v9.52.0
Livewire v2.12.0
Alpine js v3.10.3
Async-alpine v1.0.0
Vite v3.2.5

When I try to use the $wire object, I get an error . Sample code below.

Component js:
image

Register js components:
image

Blade component:
image

Error:
image
image

Doesn't support dynamic content

If content is loaded with ax-load present, it won't be handled as an asynchronous component.

This may be tricky to implement, we'd have to use a mutation observer and ensure the DOM is changed before Alpine's mutation observer can be triggered.

This would prevent Async Alpine from working with client-side routers and similar, which is a fairly major area that Alpine works well in.

Needs more research.

Testing pages

I am currently testing fixes, tweaks and additions against client sites which often have a lot going on and may not have a need for what I'm working on. This adds overhead to testing new changes.

I'd like some form of testing within this repo, not currently sure to what extent.

The basic would be simply a set of pages that load the latest version and apply it in several simple use-cases that can be manually checked.
Could also look into testing frameworks to make it more automated, I wonder if I can see how Slinkity handles their tests for inspiration.

`x-ref` seems to not be initialised

Appears to be happening on at least Alpine version 3.3.3, haven't tested yet with further versions.

The attribute is being renamed, but it appears it isn't being exposed within the component.

var idle is minified to var $ witch breaks a legacy Zepto(jQuery alternative) implementation

Hi Accudio,

I use async-alpine on my web project that uses ZeptoJS(jQuery alternative) for a legacy feature. As Zepto and jQuery use $ as the main identifier my old code stops working, because your idle function is called $ in the minified version since async-alpine v1.1.0.

Is it possible to minify to another name.
Thanks for the great package and your help
Vasco

Enable multiple matches in AsyncAlpine.alias()

I have components organised as follows:

components/
  Button/
    Button.island.js
    Button.jsx

In my Vite entry file, I'm using AsyncAlpine.alias('components/[name]/[name].island.js').

As only the first instance of [name] is replaced, I get a 404 on http://localhost:5173/components/Button/[name].island.js.

If I remove the second instance of [name] and rename Button.island.js to island.js, everything works as expected.

Would you be happy to enable replacement of multiple instances of [name] in AsyncAlpine.alias()?

Allow registering async components once instead of every instance

A bit like Alpine.data() allows for registering a component for multiple uses.

Currently if you have an accordion component that sits on each accordion item you will need ax-load-src="https://..." for every instance. We could expose an API like:

AsyncAlpine.data('accordion', 'https://...')

and this would allow components named 'accordion' to omit the ax-load-src attribute.

Current state & stability

Hey!

Thank you so much for this package, it works great. We're exploring using it for filamentphp/filament v3, as it solves a whole bunch of issues for us. I've just got a couple of questions for you if that's okay...

In the README, it's said to be "experimental". Are you frequently releasing breaking changes that we should be aware of? Or is this outdated advice. Is it suitable to be used on a project with 2.5k+ daily installs?

Also, I saw your Roadmap project. Specifically this card. You mention that it can't be used as a plugin ATM. Before seeing that, I had actually done exactly that, and it seemed to work exactly how I wanted it to. Is this outdated information, or did I do something wrong, or miss something that doesn't work?

Screenshot 2022-10-13 at 14 39 26

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.