Codesandbox "Preview on edit" 不适用于 Aurelia,但适用于其他框架和 vanilla HTML

Codesandbox "Preview on edit" does not work for Aurelia but works with other frameworks and vanilla HTML

我正在使用 Codesandbox 创建示例,在一个新项目中我们正在使用框架 Aurelia。我可以在 Codesandbox 上获得 Aurelia 运行,但我无法让 Preview on edit 工作。我试图添加一个 sandbox.config.json 并将 Hard Reload on Change 设置为 true 但它没有帮助。这不是一个破坏交易的因素,但是当您习惯于立即看到您的编辑时,它会很烦人。我认为问题是使用的 TemplateStatic,但是 Codesandbox 没有提供 Aurelia 模板。有人解决了吗?

Aurelia 代码示例,请参阅文件 app.html:

https://codesandbox.io/s/n3yxrj9lwp

原版 HTML,请参阅文件 index.html

https://codesandbox.io/s/l73lnlvymq

反应,见文件 index.tsx:

https://codesandbox.io/s/7w5yx8qmz1

代码:

index.html:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Aurelia App</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</head>

<body style='font-family:arial'>
  <script src='https://unpkg.com/aurelia-script@1.3.0'></script>
    </script>
    <script>
        const aurelia = new au.Aurelia();
      aurelia
        .use
          .standardConfiguration()
          .developmentLogging();
      aurelia
        .start()
        .then(() => aurelia.setRoot('app.js', document.body))
        .catch(ex => {
          document.body.textContent = `Bootstrap error: ${ex.toString()}`;
        });
    </script>
</body>
</html>

app.js:

export class App {
  constructor() {
    this.message = "Aurelia Test";
  }
}

app.html:

<template>
  <div class="jumbotron mb-0"><h1>${message}</h1></div>
  <div class="d-flex">Preview does not work here 1</div>
</template>

使用 Aurelia Framework 1.3.0 的工作示例:

app.html

<template>
  <h1>${message}</h1>
</template>

app.js

export class App {
  message = 'Hello World!';
}

index.html

<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Aurelia App</title>
</head>

<body>
</body>

</html>

main.js

import { Aurelia } from "aurelia-framework";

export async function configure(aurelia) {
  aurelia.use.standardConfiguration().developmentLogging();

  await aurelia
    .start()
    .then(a => a.setRoot("app", document.body))
    .catch(ex => {
      document.body.textContent = `Bootstrap error: ${ex}`;
    });
}

codesandbox.js

import "aurelia-polyfills";
import { initialize } from "aurelia-pal-browser";
import { Aurelia } from "aurelia-framework";
import { Origin } from "aurelia-metadata";
import { Loader, TemplateRegistryEntry, LoaderPlugin } from "aurelia-loader";
import { DOM, PLATFORM } from "aurelia-pal";
import { join } from "aurelia-path";

// IMPORTANT
// The code in this file is not needed in a real Aurelia app.
// It is only needed to configure CodeSandbox.io for Aurelia.
// Aurelia application code begins in the src/main.ts file.
// ORIGINAL AUTHOR: Bazyli Brzóska https://github.com/niieani

class TextTemplateLoader {
  async loadTemplate(loader, entry) {
    const text = await loader.loadText(entry.address);
    entry.template = DOM.createTemplateFromMarkup(text);
  }
}

function ensureOriginOnExports(moduleExports, moduleId) {
  let target = moduleExports;
  let key;
  let exportedValue;

  if (!moduleExports) {
    return moduleExports;
  }

  if (target.__useDefault) {
    target = target.default;
  }

  Origin.set(target, new Origin(moduleId, "default"));

  if (typeof target === "object") {
    for (key in target) {
      exportedValue = target[key];

      if (typeof exportedValue === "function") {
        Origin.set(exportedValue, new Origin(moduleId, key));
      }
    }
  }

  return moduleExports;
}

async function getModule(moduleName) {
  // if (moduleName.includes("/")) {
  //   moduleName = join("src", moduleName);
  // }

  const hasJS = moduleName.endsWith(".js");

  try {
    return await import(`${moduleName}` /* webpackMode: 'eager' */);
  } catch (e) {}

  try {
    return await import(`./${moduleName}` /* webpackMode: 'eager' */);
  } catch (e) {}

  try {
    return await import(`${moduleName}/dist/amd/${moduleName}` /* webpackMode: 'eager' */);
  } catch (e) {}

  try {
    return await import(`./${moduleName}` /* webpackMode: 'eager' */);
  } catch (e) {}

  if (moduleName.includes("/")) {
    try {
      const [dep, ...path] = moduleName.split("/");
      return import(`${dep}/dist/amd/${path.join(
        "/"
      )}` /* webpackMode: 'eager' */);
    } catch (e) {}
  }

  if (!hasJS) {
    return await getModule(`${moduleName}.js`);
  }
}

class SandboxLoader extends Loader {
  moduleRegistry = Object.create(null);
  loaderPlugins = Object.create(null);
  modulesBeingLoaded = new Map();

  templateLoader: TextTemplateLoader;

  constructor() {
    super();

    this.useTemplateLoader(new TextTemplateLoader());
    this.addPlugin("template-registry-entry", {
      fetch: async moduleId => {
        const entry = this.getOrCreateTemplateRegistryEntry(moduleId);
        if (!entry.templateIsLoaded) {
          await this.templateLoader.loadTemplate(this, entry);
        }
        return entry;
      }
    });
  }

  async _import(address, defaultHMR = true) {
    const addressParts = address.split("!");
    const moduleId = addressParts.splice(addressParts.length - 1, 1)[0];
    const loaderPlugin = addressParts.length === 1 ? addressParts[0] : null;

    if (loaderPlugin) {
      const plugin = this.loaderPlugins[loaderPlugin];
      if (!plugin) {
        throw new Error(
          `Plugin ${loaderPlugin} is not registered in the loader.`
        );
      }
      return await plugin.fetch(moduleId);
    }

    const m = await getModule(moduleId);
    return m;
  }

  map(id, source) {}

  normalizeSync(moduleId, relativeTo) {
    return moduleId;
  }

  normalize(moduleId, relativeTo) {
    return Promise.resolve(moduleId);
  }

  useTemplateLoader(templateLoader) {
    this.templateLoader = templateLoader;
  }

  loadAllModules(ids) {
    return Promise.all(ids.map(id => this.loadModule(id)));
  }

  async loadModule(moduleId, defaultHMR = true) {
    let existing = this.moduleRegistry[moduleId];
    if (existing) {
      return existing;
    }
    let beingLoaded = this.modulesBeingLoaded.get(moduleId);
    if (beingLoaded) {
      return beingLoaded;
    }
    beingLoaded = this._import(moduleId, defaultHMR);
    this.modulesBeingLoaded.set(moduleId, beingLoaded);
    const moduleExports = await beingLoaded;
    this.moduleRegistry[moduleId] = ensureOriginOnExports(
      moduleExports,
      moduleId
    );
    this.modulesBeingLoaded.delete(moduleId);
    return moduleExports;
  }

  loadTemplate(url) {
    return this.loadModule(
      this.applyPluginToUrl(url, "template-registry-entry"),
      false
    );
  }

  async loadText(url) {
    const result = await this.loadModule(url, false);
    if (result.default && "string" == typeof result.default) {
      // we're dealing with a file loaded using the css-loader:
      return result.default;
    }
    return result;
  }

  applyPluginToUrl(url, pluginName) {
    return `${pluginName}!${url}`;
  }

  addPlugin(pluginName, implementation) {
    this.loaderPlugins[pluginName] = implementation;
  }
}

(async () => {
  try {
    initialize();
    const aurelia = new Aurelia(new SandboxLoader());
    await getModule("./main").then(m => m.configure(aurelia));
  } catch (ex) {
    console.error(ex);
    document.body.textContent = ex;
  }
})();

package.json

{
  "name": "a-simple-component",
  "version": "1.0.0",
  "private": true,
  "keywords": [],
  "description": "An Aurelia application that shows how to build a simple component.",
  "main": "codesandbox.js",
  "dependencies": {
    "aurelia-event-aggregator": "1.0.1",
    "aurelia-framework": "1.3.0",
    "aurelia-history-browser": "1.2.0",
    "aurelia-loader": "1.0.0",
    "aurelia-logging": "1.5.0",
    "aurelia-logging-console": "1.0.0",
    "aurelia-metadata": "1.0.4",
    "aurelia-pal": "1.8.0",
    "aurelia-pal-browser": "1.8.0",
    "aurelia-polyfills": "1.3.0",
    "aurelia-router": "1.6.3",
    "aurelia-templating": "1.10.1",
    "aurelia-templating-binding": "1.5.2",
    "aurelia-templating-resources": "1.7.1",
    "aurelia-templating-router": "1.3.3"
  }
}

https://codesandbox.io/s/849oxmjm82

Aurelia Framework 1.0.7 示例:

https://codesandbox.io/s/4ql5qvml49