single-spa / single-spa-alpinejs

Single-spa helpers for alpinejs
MIT License
9 stars 0 forks source link

Application fails to mount when xInit is defined and the application name has special characters #4

Closed tsukhu closed 4 years ago

tsukhu commented 4 years ago

When xInit attribute and the single spa application name has special characters like - , @, + , : etc. alpine js fails when it tries to execute the xInit function

To reproduce:

const myFn = () => Promise.resolve(console.log('Hello'));
const appTemplate = (props) = Promise.resolve(`
<div class="mui-container">
<div>
<div class="mui-panel">
<div class="mui--test-display1"> Test x-show</div>
    <button class="mui-btn mui-btn--primary" @click="open = !open">
      Open/Close
    </button>
    <div x-show="open" class="mui--text-display4">
      Hey, I'm open
    </div>
    </div>
    <div class="mui-panel">
    <div class="mui--test-display1"> Test x-model input binding</div>
    <div x-data="{ name: 'Single SPA Integrated AlpineJS'}">
      <div class="mui-textfield">
        <input type="text" name="name" id="name" x-model="name" />
      </div>
      <div class="mui--test-display2">
        My name is <span x-text="name"></span>
      </div>
    </div>
    </div>
    <div class="mui-panel">
    <div class="mui--test-display1"> TODO App Test </div>
    <div x-data="{ todos: ['Learn Single-SPA', 'Try AlpineJS'], newTodo: 'Integrate'}">
      <div class="mui-textfield">
        <input type="text" name="todo" id="todo" x-model="newTodo" />
      </div>
      <button class="mui-btn mui-btn--primary" @click="todos.push(newTodo)">
        Add
      </button>

      <table class="mui-table">
        <thead>
          <tr>
            <th>Task</th>
            <th>Action</th>
          </tr>
        </thead>
        <tbody>
        <template x-for="todo in todos" :key="todo">
          <tr>
            <td x-text="todo""></td>
            <td><button class="mui-btn mui-btn--small mui-btn--fab mui-btn--danger"  @click="todos = todos.filter(item => item !== todo)">
            -
          </button></td>
          </tr>
          </template>

        </tbody>
      </table>

    </div>
  </div>
  </div>
  <div class="mui-panel">
  <div class="mui--test-display1"> Test x-bind to change background color (red/purple) on even/odd numbers </div>
  <div x-data="{ count: 0}">
    <div class="mui-textfield">
      <input type="text" name="count" id="count" x-model="count" />
    </div>
    <div x-bind:class="{ 'mui--bg-color-red-500': count %2 === 0, 'mui--bg-color-purple-500': count %2 !== 0}">
      Big when even
    </div>
  </div>
  </div>
  </div>
`);

// Initialize Alpine JS App
const alpineApp = window.singleSpaAlpineJs({
  template: (props) => appTemplate,
  xData: () => Promise.resolve({ open: false }),
  xInit: () => myFn
});

singleSpa.registerApplication({
  name: "alpinejs-App", // THIS HAS SPECIAL CHARACTERS 
  app: alpineApp,
  activeWhen: () => window.showAlpineApp, //parseQuery(document.location.search).app === "alpine",
});

On execution the single spa help will add a x-init function call to the dom

x-init="singleSpaAlpineXInit.alpinejs-App('alpine-alpinejs-App')" // DOES NOT WORK

Due to this alpinejs throws the following error:

alpine.js:1738 Uncaught ReferenceError: App is not defined
    at eval (eval at o (alpine.js:112), <anonymous>:3:75)
    at o (alpine.js:112)
    at le.evaluateReturnExpression (alpine.js:1581)
    at new le (alpine.js:1350)
    at Object.initializeComponent (alpine.js:1735)
    at alpine.js:1722
    at alpine.js:1700
    at Array.forEach (<anonymous>)
    at Object.discoverUninitializedComponents (alpine.js:1699)
    at alpine.js:1721

Possible Solution

function normalizeString(str) {
  return str.replace(/[^a-z0-9,. ]/gi, '_')
}
let xInitFnName = `${normalizeString(name)}('alpine-${name}')` // where the name is the application name
tsukhu commented 4 years ago

resolved with PR #5