Giter Site home page Giter Site logo

Comments (88)

davismj avatar davismj commented on May 14, 2024 5

From an API point of view, I vote option 1, or option 2 as <require from="./hello.html" />. I agree the option 3 will lead to a very crowded and hard to read line.

from aurelia.

StrahilKazlachev avatar StrahilKazlachev commented on May 14, 2024 3

I don't think that reintroducing <require> with limitations or known issues is a good move.
I think it should be all or none.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024 3

I think we should keep this the same as vCurrent. Any real objections to that?

from aurelia.

StrahilKazlachev avatar StrahilKazlachev commented on May 14, 2024 1

If we keep any declarative form of dependencies declaration in the view, that supports css, we need to resolve the css order issue.
I can't find the original issue, so in short: the <require> syntax mirrors the ES import, so order is irrelevant, but when it comes to importing css order matters.
I suppose we can either approach this by syntax or by "executing" the imports sequentially.
Examples(do not view as proposition):

<require from="vendors/bootstrap.css">
  <require from="./app.css"></require>
</require>

I understand the above makes the parsing somewhat more complex, but we need to resolve this in one way or another.

from aurelia.

fkleuver avatar fkleuver commented on May 14, 2024 1

Whatever syntax we choose should work in JIT mode. I really don't want to require a full HTML parser to be embedded inside the JIT.

As long as we choose a syntax that is compatible with the HTML spec (e.g. the browser can parse it) then we don't need to. The AOT's parser and the browser's parser would work the same way. The AOT's parser would just be more efficient and produce a better performing runtime

from aurelia.

fkleuver avatar fkleuver commented on May 14, 2024 1

@Sayan751 Yep. I believe @EisenbergEffect is only testing locally with a WIP require plugin

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024 1

@Sayan751 The vNext runtime and compiler themselves don't contain any notion of how dependencies for a template are loaded, only that when the template is compiled or executed, the dependencies should be present. As we move forward, things like require will most likely be handled inside the AOT system or loader plugins for those who don't want to use AOT or can't.

A few weeks ago I started experimenting with writing a vNext app. As part of doing that, I built a require.js plugin for JIT-mode development that handles require/import elements, HTML-only elements, and CSS imports. I shared a bit about my personal experiment in this RFC: #375

@fkleuver I was planning to fix up the current plugin-requirejs package based on what I had built for my own app. It needs some refactoring to make it more generic, but I could create a branch and start working on that this week. It would enable some of our earlier adopters/experiments to work with vNext in a way that's more ergonomic in advance of AOT. What do you think?

from aurelia.

thomas-darling avatar thomas-darling commented on May 14, 2024 1

I’m strongly in favor of the <import> outside the <template>, so yes, that’s the proposal I’d vote for, @EisenbergEffect .

The <link> element is tempting, but I’m leaning towards not mixing those things up. The thing is, it would not be a normal link, so if we used that, then we would:

  1. violate the spec, as it clearly states that a <link> element must have a rel attribute.

  2. have to explain how and why our <link> is different from the spec - for example, our as attribute has a different meaning, there should be no rel, and all other attributes are invalid.

We would of course need documentation for this thing no matter what, but I think there will be less potential for confusion if we have our own thing, instead of a standard thing that behaves in a non-standard way.

The really fun example is this one:
What happens if we put a <link> to a stylesheet in our template - should that have a rel attribute, and if not, why not, given that the spec says it should? This could be confusing to new users.

Regarding naming, I definitely think import is the best name. That’s what this concept is called in ES, so we should align with that, to keep things consistent - require sounds way too much like a legacy or node.js thing to me.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024 1

My current require.js plugin handles both require and import. It doesn't distinguish between inside or outside of the template at the moment. It's just a prototype though.

I don't see any issue in supporting what @thomas-darling suggests. We can effectively remove require by not documenting it anywhere except in the migration docs as a backwards compat feature which will officially removed at some future release TBD. Newcomers don't even need to know that option exists.

from aurelia.

fkleuver avatar fkleuver commented on May 14, 2024 1

Hm didn't we discuss this somewhere else already? I honestly see zero issues with having both. It's 3 extra lines:

function preparseTemplate(html) {
  const imports = [];
  const len = html.length;
  let i = 0;
  let start = 0;
  let ch = 0;
  while (i < len) {
  if (html.charCodeAt(i) === 0x3C) {
    ch = html.charCodeAt(i + 1);
    if (ch === 0x72 && html.charCodeAt(i + 2) === 0x65 && html.slice(i + 3, i + 8) === 'quire') {
        start = i = i + 17;
      while (html.charCodeAt(i++) !== 0x22);
      imports.push(html.slice(start, i));
    } else if (ch === 0x69 && html.charCodeAt(i + 2) === 0x6D && html.charCodeAt(i + 3) === 0x70 && html.slice(i + 4, i + 7) === 'ort') {
        start = i = i + 16;
      while (html.charCodeAt(i++) !== 0x22);
      imports.push(html.slice(start, i));
    }
  }
    ++i;
  }
  return imports;
}

It parses the the average template with a couple of imports/requires in less than 0.1ms and that's without any optimization attempt or restrictions on where they are placed (the entire html string is parsed). What's the harm?

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024 1

Let me give a quick explanation that describes what basically happens:

Let's say you have resources/index.ts and it looks something like this:

export * from './elements/index';
export * from './attributes/index';

And in elements/index.ts you have something like this:

export * from './hello-world';
export * from './goodbye-world';

And in hello-world.ts you have something like this:

@customElement('hello-world')
export class HelloWorld {
  ...
}

Assume similar patterns for the other files that are imported.

Now, let's say that you put this into your my-app.html view:

<import from="./resources/index"></import>

That's going to turn into something similar to this in code:

import resources from './resources/index';
import template from './my-app.html';

@customElement({
  name: 'my-app',
  template,
  dependencies: [resources]
})
export class App {
}

The dependencies array for the element will eventually get passed along to the DI container for the element, something like this:

const definition = {
  name: 'my-app',
  dependencies: [resources]
};

const container = createContainerForElementClass();
container.register(...definition.dependencies);

The register method of the container checks to see whether its argument is a registry or if any of its properties are a registry. Because the dependency above is a module object itself, this means that it will have a property for every export. Since we used star exports aggregated up, it means that the final module object will have a property for every single export under the resources folder. Any class that has a registration decorator (e.g. @singleton or @transient) functions as a registry. Every custom element, custom attribute and all other resource types are registries because their @customeElement, etc. decorators effectively apply behaviors similar to @transient.

The end result of this is that a single import can bring in an entire collection of resources for use within a view. So, even if you don't want to use global resources, you can still have a way to import a standard set of resources with a single import in your view.

Now, on to the proposal regarding these two being the same:

<import from="components/index"></import>
<import from="components"></import>

That's really up to the module loader and/or AOT process. This is the way it would work in node.js. I believe that system.js works this way and that require.js can be made to work this way as well. However, it is not the way that the WHATWG standard module loader operates at present. I believe some of the currently being discussed improvements to the standard loader, enabling configuration of paths, etc., would enable this in the future. However, it's not going to work automatically in any of the cases above, except Node, I believe.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Actually, option three is kind of nice. Not sure if it would get crowded though. I'm pretty open on syntax as long as it's something we can extract inside of a loader plugin without needing to include an entire html parser to do it. The trick is that this data has to be extracted before the template is sent to the compiler and we want to avoid double parsing the html.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

auto-trace cli already has htmlparser2 installed to deal with <require> tag.
aurelia-webpack-plugin also has access to webpack's html parser for same purpose.

The parsing part is not a problem. The extra parsing is in compile time, I don't think we have double parsing in runtime.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

I got your point now. I think you are talking about dynamic component loading at runtime (supported by jit app).

We can enforce only support require attribute if it's the first attribute of template tag. I think it's a good trade-off for both syntax and usability.

This also makes the "view!" plugin easier to remove the require tag from cleanedTemplate.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

Probably option1 fits better with Aurelia's spirit of standard compliant.

In HTML5 browser native parser, <require from="./hello.html" /> is treated exactly same as <require from="./hello.html">, result is same as missing closing pair. But I like the compactness.

from aurelia.

davismj avatar davismj commented on May 14, 2024

Can we eliminate that use case completely, and limit <require> to Aurelia HTML behaviors?

from aurelia.

3cp avatar 3cp commented on May 14, 2024

What about a variant of option 3?

<template
  require="./h.html"
  require="./h.css"
>
</template>

This is valid html. The order of attributes are not an issue on IE/Edge, as require attributes will be extracted out by regex (or some nodejs html parser at bundling time) in view plugin, not by native browser html parser.

from aurelia.

fkleuver avatar fkleuver commented on May 14, 2024

Let's not worry about complexity of parsing. I'm going to build a html parser for the aot module anyway, it will be spec compliant, and we should be able to add a few custom rules to it specific to Aurelia. During AOT we can parse the html to extract out any requires as well as have the template compiler process it in the same pass. There are ways to do that.
So whatever gives the nicest API is what we should go with.

from aurelia.

StrahilKazlachev avatar StrahilKazlachev commented on May 14, 2024

@fkleuver And that will work with the JIT also? Or we will have AOT only features?

I find it confusing having multiple definitions of the same attribute.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Right now there's no notion of the require syntax anywhere in the core. The core expects a list of dependencies, and doesn't care where they come from. This syntax only exists inside the requirejs plugin, which extracts the paths and uses them to load the modules so that it passes the dependencies along to the compiler. This turns out to massively simplify many, many things.

Whatever syntax we choose should work in JIT mode. I really don't want to require a full HTML parser to be embedded inside the JIT.

from aurelia.

fkleuver avatar fkleuver commented on May 14, 2024

I really don't want to require a full HTML parser to be embedded inside the JIT.

Of course not. JIT is a runtime thing, we have the browser to parse HTML there. I'm talking strictly about AOT here. AOT is running in nodejs runtime so you need an HTML parser anyway.

For JS/TS parsing in AOT we have the excellent typescript library that is maintained by a company with a lot of resources and smart people, so that's always going to be a safe bet.

There is no such thing for HTML / CSS as a standalone nodejs library so I'd prefer to do that ourselves. It is comparatively simple enough (with a core syntax that hardly ever changes) that we can do that ourselves.

Having our own HTML parser for AOT also means we can inject custom element processing and the sorts directly in there, save on the number of passes we need to do, and perhaps even end up with simpler code in the end. Not to mention the build time performance would be much better (not that this is a huge concern, but for a large business app it's nice to have a 30 second AOT processing time instead of a 2 minute one)

from aurelia.

fkleuver avatar fkleuver commented on May 14, 2024

@fkleuver And that will work with the JIT also? Or we will have AOT only features?

AOT in itself is a feature that only exists in, well, AOT. I wouldn't call any particular syntax "AOT only feature" though. That would imply you can do stuff in AOT that you can't do with the JIT. But AOT has much more information about the whole project available than the runtime ever could, so it allows you to write cleaner code by having to declare fewer things explicitly because the AOT can figure it out and glue it together

from aurelia.

m-gallesio avatar m-gallesio commented on May 14, 2024

As possible relevant note, @anything clashes with ASP.NET Razor syntax which uses @ to introduce its own directives. It can be escaped (if used in a Razor .cshtml the line would be @@import './hello.html';), but it feels slightly cumbersome.

from aurelia.

fkleuver avatar fkleuver commented on May 14, 2024

Yeah I don't think we need to change it compared to vCurrent. It works fine doesn't it?

from aurelia.

thomas-darling avatar thomas-darling commented on May 14, 2024

I mostly agree - the current <require> element is the nicest way to do this.

I don't think it matters much whether it is inside or outside the <template> element, although I guess having it outside might actually feel slightly more natural. Either one is fine though.

Personally, I also wouldn't mind if it was renamed to <import>, just to keep the naming consistent with ES6. I've caught myself writing that by mistake several times, and although it would be a breaking change, it would also be super easy to rename with a global search and replace :-)

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Funny enough, we originally called it import in the very, very early days of Aurelia but then discovered there was an issue with IE. I think it was IE10 but can't remember if it was fixed in later versions. I do and have always liked import better. We could enable it for vNext and still support require at the same time. It's mostly going to be handled inside either a loader plugin or AOT where this is pretty trivial. (It's actually not baked in anywhere into the runtime.) @fkleuver What are your thoughts?

from aurelia.

fkleuver avatar fkleuver commented on May 14, 2024

I don't see any issues with having both. Probably negligible parsing overhead.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

@huochunpeng How hard would it be to include <import from="..."> in the current CLI's tracing? I'd like to enable my vNext require.js plugin to support this but would also need equivalent support in the CLI's bundler. Thoughts?

from aurelia.

3cp avatar 3cp commented on May 14, 2024

Super easy. You can try to modify your local cli find-deps.js findHtmlDeps.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Excellent to hear. I'll modify it in my local copy and try it out.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Ok, that was super easy :) I can send a PR to the CLI. Are there tests on this particular area that I should extend @huochunpeng ?

from aurelia.

3cp avatar 3cp commented on May 14, 2024

@thomas-darling we have to move require/import elements out of template element, because vCurrent has a very painful and confusing limitation.

If you have a component

<template>
  <require from="..."></require>
  <td></td>
<template>

Then try to use it as a tr

<tr as-element="my-comp"></tr>

It is an error because HTML standard doesn’t allow any tag other than th/td inside a tr element! There is nothing aurelia can work around since aurelia uses native browser html parser.

Moving require/import out of template can avoid vNext to fight html standard.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

I don't actually understand the problem here. The <require> elements should be removed from the template before it's compiled anyway. Also, if they are outside the template, then in a single file components setup, where would they go?

from aurelia.

3cp avatar 3cp commented on May 14, 2024

It certainly doesn’t work in vCurrent, there was some github issue on require inside tr.

I don’t think it’s an issue for future single file component format. The root is html format anyway, it is easy for compiler.

<import from=""></import>
<template></template>
<script></script>
<style></style>

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

My point is that the require should never exist inside the tr. It should be removed long before the template is instantiated and pushed into the tr. It sounds like there's a bug in vCurrent somewhere, not so much in the design of require/import.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

I see you were talking about import tag inside template in vNext. Yes, it would not be an issue since we strip them.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

They should be stripped in vCurrent as well, I thought. If not, we should fix that for sure.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

In vCurrent, the resource loading is delayed to runtime when it sees the require element in DOM. If I am not wrong.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

They should be getting removed here: https://github.com/aurelia/loader/blob/master/src/template-registry-entry.js#L82 This happens when the module loader loads a template, more or less.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

If that is before the html fragment is appended to DOM, I need to test why vCurrent has issue in tr. Unless @bigopon knew something already.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

It is before it's even associated with a particular custom element. So, I think there may be something else going on here.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

Ref aurelia/binding#409 (comment)

from aurelia.

3cp avatar 3cp commented on May 14, 2024

Update: the <tr as-element with require tag thing seems working fine now with current vCurrent. Strange. Something must have changed. I will test on IE and Edge when I got a chance next week.

from aurelia.

Sayan751 avatar Sayan751 commented on May 14, 2024

Just a question to avoid (my) confusion. I am trying v0.3.0-dev.20190117. But, neither the @import '' nor the <require from=''> syntaxes are working. Is this something, still to be implemented?

from aurelia.

fkleuver avatar fkleuver commented on May 14, 2024

@EisenbergEffect Sounds good!

from aurelia.

3cp avatar 3cp commented on May 14, 2024

Update: the tr require thing works in IE and Edge too. Now I am not sure what happened before when I encountered that issue.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

@huochunpeng Try it with two requires instead of one. I'm wondering if it's something to do with the implementation looping and removing things from a live node list going wrong.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

@EisenbergEffect two requires are fine. I found how to reproduce the bug. It's a combination of require and repeat.

<template>
  <require from="./hello"></require>
  <td repeat.for="v of [1,2,3]"><hello></hello> ${v} ${item}</td>
</template>

It supposes to render 3 td, but only 1 appears.

  1. Remove the require tag, it renders ok.
  2. Move require tag to be inside td, it renders ok.

Might be a repeater bug.

Use this repo https://github.com/huochunpeng/au-require-debug

from aurelia.

bigopon avatar bigopon commented on May 14, 2024

This is due to how native parser parse the template I believe, when tr, td are not the only child, it removes other elements

from aurelia.

3cp avatar 3cp commented on May 14, 2024

Thx! yes, I can reproduce the problem without aurelia.

var t = document.createElement('div');
t.innerHTML =`<template>
  <require from="./hello"></require>
  <td repeat.for="v of [1,2,3]"><hello></hello> \${v} \${item}</td>
</template>`;
console.log(t);
[Log] <div>
<template>
Template Content
<require from="./hello"></require>
<hello></hello>
" ${v} ${item}"
</template>
</div>

The td is gone. That happens with or without repeat.for.

@EisenbergEffect that's a valid point we must move require/import out of template element.

from aurelia.

thomas-darling avatar thomas-darling commented on May 14, 2024

Actually, if we are renaming this thing anyway, we could just add support for the new <import> - which is then only allowed outside the <template>.

Then we can leave the old <require> support as-is, but deprecate it and remove it later, in a minor version release. That way, people will have some time to update their projects...

But then again, vNext is a major version anyway, so personally I'd be fine with just taking the hit now, and keep things clean in vNext. It’s just a suggestion in case we really wanted to avoid breaking this.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

vNext has extra immunity to the browser parser limitation. The template in vNext is preprocessed by a small parser (not native browser parser) to strip require/import elements. So you would not encounter the browser limitation in vNext even when you put require element inside template element.

from aurelia.

davismj avatar davismj commented on May 14, 2024

Looks like @import is out.

<require> can not be inside or outside of the template tag.

Is there any reason to add thew new <import> syntax?

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

So, is this the proposal?

<import from="./hello"></import>

<template>
  <td repeat.for="v of [1,2,3]"><hello></hello> ${v} ${item}</td>
</template>

I also started to wonder...why not use the link tag?

<link href="./hello">

<template>
  <td repeat.for="v of [1,2,3]"><hello></hello> ${v} ${item}</td>
</template>

Basically, let Aurelia handle any link without a rel. Not sure if this would work or if we should do it, but thought I'd toss it out here.

from aurelia.

davismj avatar davismj commented on May 14, 2024

or . Since both are non-standard I say we keep to our existing require.

<link rel="import" href="./hello" /> Is the currently proposed HTML standard. I'm not sure what <link href="./hello"> will do in all browser by default, but my guess is that it will try to fetch. I dunno if that's a good thing or an undesired side effect.

from aurelia.

davismj avatar davismj commented on May 14, 2024

I mostly agree, but

That’s what this concept is called in ES, so we should align with that, to keep things consistent

But this isn't EcmaScript, this is HTML.

In any case, and both seem best.

from aurelia.

thomas-darling avatar thomas-darling commented on May 14, 2024

@davismj I know what you mean - but at least there will be some consistency then - if we go with require there will be no consistency anywhere, except with node.js, which is just confusing.

We aready have the standard import in ES and the standard link in HTML - I see no reason to introduce require as a third name, when it behaves pretty much exactly like an import in ES.

from aurelia.

davismj avatar davismj commented on May 14, 2024

We already have <require> in current, which makes it the strongest option.

from aurelia.

thomas-darling avatar thomas-darling commented on May 14, 2024

That's why I was arguing earlier, that we should maybe keep require as-is (i.e. use inside the template), but deprecate it, and introduce <import> as the new way of doing it, outside the template.
Then we can remove require in a future, minor release.

If we have to move this thing anyway, then there's minimal effort required to also rename it.
Aurelia still has a relatively small user base, but a huge potential - so we should design for the future, not for the past, and right now we have a good opportunity to rename this thing to something better.
We won't get that again anytime soon 🙂

from aurelia.

davismj avatar davismj commented on May 14, 2024

Then we can remove require in a future, minor release.

Would be a major release, though. Breaking changes and all.

Aurelia still has a relatively small user base, but a huge potential - so we should design for the future, not for the past, and right now we have a good opportunity to rename this thing to something better.

100%, but this is just a minor naming thing. And we don't want to make more work for our loyal developer base unless they get something out of it.

from aurelia.

thomas-darling avatar thomas-darling commented on May 14, 2024

This can be renamed in 30 sec though - just do a global search and replace in **/*.html 😉

<require (.*?)></require> -> <import $1>

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

I think we're good.

from aurelia.

davismj avatar davismj commented on May 14, 2024

So we have two custom elements, and a single file that exports them.

components/index.ts

export { OneCustomElement } from './one';
export { TwoCustomElement } from './two';

I propose that

<import src="components/index"></import>

and

<import src="components"></import>

should have the same effect as

<import src="components/one"></import>
<import src="components/two"></import>

from aurelia.

3cp avatar 3cp commented on May 14, 2024

I am going to do some preprocess on html.

@EisenbergEffect the information you provided above seems different from vCurrent.

<import from="./foo"></import>

<template>
  ...
</template>

The deps become:

import foo from './foo';
@customElement({
  name: 'my-app',
  template, // with only <template>
  dependencies: [foo]
})
...

But vCurrent convention says the import should be import { Foo } from './foo'; with dependencies: [Foo]. Please clarify the behaviour in vnext. I knew vnext has no need for the convention assumption, because every resources inside ./foo have explicit decorators.

If that is the case, if ./foo defined custom element FooA and FooB, the single import <import from="./foo"></import> will make both <foo-a> and <foo-b> available in the html template.

Update the import foo from './foo'; seems incorrect, because it only gets the default export, it cannot see other exports.

from aurelia.

fkleuver avatar fkleuver commented on May 14, 2024

I think we should be looking at native html modules actually, and make sure it will be compatible with that.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

I had imagined that this:

<import from ‘./foo’></import>

would turn into this:

import * as foo from ‘./foo’;

So that this could be done:

customElement({
  dependencies: [foo]
}
export class Bar {
}

All the dependencies get passed to the vNext DI container’s register method, which can handle two specific scenarios:

  • An object with a register method. (Or a module that exports a register function, since a module is just an object).
  • If no register function is found, the keys of the object are iterated to see if any of them have values with a register method.

In this way, any ES module can be passed directly to the container’s register method and the user can choose to imperatively add dependencies via implementing register, or just export (or re-export) other things which have register methods. Decorators like customElement, customAttribute, etc. generate a static register method on the class, so that any module that exports these, which is passed to the container’s register method, will get registered in the container according to the rules of that resource.

Hopefully this all makes sense…

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

One crazy idea I hadn’t thought of could be to turn views into a dependencies as well. So, given an HTML file like this:

<import from=‘./foo’></import>

<div>
  <foo></foo>
</div>

The compiler could turn that into this JS module:

export default view = new CompiledViewHere();
export * from ./foo’;

Assuming that CompiledView implements a register method, this entire module could be passed as dependencies. We would need to make a change so that the view was looked up using a special key from the DI container.

Just brainstorming…

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Hmm. This wouldn’t quite work for html only custom elements though, as importing those would result in the view for another element getting registered, so there would have to be something a bit different. One idea is to just generate a register method and then enable it to register things differently in different contexts. Again, not sure all the details there, just thinking out loud…

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Here’s another idea. Given this:

my-element.html

<import from=“./foo”></import>
<import from=“./bar.html></import>

<div>
  <foo></foo>
  <bar></bar>
</div>

We could turn that into this:

import * as foo from './foo';
import { getHTMLOnlyElement as getBar } from './bar.html';

const bar = getBar(); 

export const name = 'my-element';
export const template = 'html or compiled view here';
export const dependencies = [foo, bar];

export function getHTMLOnlyElement() {
  return CustomElement.define({ template, dependencies });
}

And then the custom element would do this:

my-element.js

import * as myConfig from ./my-element.html’;

@customElement(myConfig)
export class MyElement {
}

No custom DI needed now. This should “just work”.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

One complication to this is that if someone imports something with an .html extension, it could be an html only element, an html module with a named element export, or an html module with an html only element. So, we might need some sort of helper function to test the shape of the module and determine what the actual import is:

import * as foo from './foo';
import * as barModule from './bar.html';

const bar = getHTMLOnlyElementOrHTMLModuleExportFrom(barModule);

export const name = 'my-element';
export const template = 'html or compiled view here';
export const dependencies = [foo, bar];

export function getHTMLOnlyElement() {
  return CustomElement.define({ template, dependencies });
}

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

And I suppose that the AoT process wouldn’t really need that helper function in the end, as it would be able to evaluate the shape of the import at compile-time. But, as a first pass, we could use a helper like this if needed.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

This all looks doable and clean.

One thing I want to highlight, it's that the dependencies are handled by html module. This is very important to keep transpiling as close as possible to one-to-one operation for .js file (when you mutate html file, you don't have to update js file). The one-to-one is important for watch mode.

There is one small issue in watch mode I have been thinking. When user created a new foo.js, the foo.html is yet to be created, foo.js will get transpiling without decorator (because we don't know if it's an element or just plain js class). Then user creates foo.html, we have to somehow tell the watcher to update foo.js transpiling too.

If no register function is found, the keys of the object are iterated to see if any of them have values with a register method.

I am not clear, does this step need to be recursive?

Question: is the described .register() behaviour implemented? If not, I can hardly test my work.

One idea I can think of to avoid the verbose helper func to check the shape of html module (our or native) , is to build the checker right into .register() logic.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

The register logic is part of the core DI. It’s been implemented for over a year :) We don’t want that to be recursive. The code I show above should work today, if generated during build.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

Understand, my question around recursion is for the usage of following.

some-entry.js

export * as foo from 'au2-foo-plugin';
export * as bar from 'au2-bar-plugin';

Then you can just call

export * as some from 'some-entry';
(...).register(some);

Without recursion, I guess some-entry can export a register func, then manually call .register(foo) and .register(bar) in the register func. Is my interpolation right?

Update, my bad, I guess this should work:
some-entry.js

export * from 'au2-foo-plugin';
export * from 'au2-bar-plugin';

from aurelia.

3cp avatar 3cp commented on May 14, 2024

I also have some concern around this:

export * as foo from 'foo';
(...).register(foo);

By esm standard, foo is a namespace which is NOT a JavaScript variable. The whole thing works now because in practice, foo is a JavaScript variable in current world.

Should future world strictly follows the esm standard, then is it right to pass a namespace to a function as parameter?

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Good point about re-exporting. No, that won’t work. You would have to explicitly re-export each symbol or provide a register function that was exported. I’m afraid to make the register method generally recursive…maybe there’s some way to detect if something is a module object itself and if so, then and only then to iterate its properties.

Regarding the concern in the 2nd post, I wouldn’t be worried about that. foo is a reference to the module object itself, which has a const property for every export. That should always work.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Also to note export * from ‘au2-foo-plugin’ would enable the exports to be registered, but if you do export * as foo from 'au2-foo-plugin';, that’s not going to work.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

@EisenbergEffect question: aurelia v1 has implementation to inject css to html head, does Aurelia 2 have the feature too? Or Aurelia 2 defers the task to bundler?

I am thinking about how to deal with <import from="bootstrap/dist/css/boostrap.css"></import>.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

@EisenbergEffect I am thinking of change your proposal
from

export const name = 'my-element';
export const template = 'html or compiled view here';
export const dependencies = [foo, bar];

to just

export default 'html or compiled view here';
export const dependencies = [foo, bar];

So that when user do manually import template form './a.html', they can still get a string back, this is least surprising (match existing behaviour like webpack's html-loader).

Then the injected code in my-element.js will be like:

import template, {dependencies} from ./my-element.html’;

@customElement({
  name: 'my-element',
  template,
  dependencies
})
export class MyElement {
}

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

@3cp I like the idea of exporting the html as the default export. That is intuitive and expected based on current text-type plugins for various bundlers. However, I think we should also export it as the template property and we should include name (based on file name). This enables simple manual configuration for non-conventional scenarios. I’ll probably want to add other exports to this as well, based on some of the vNext work I’ve been doing with require.js. For example, the associateView decorator that attaches a view to a class without making that class into a custom element, so that compose can render it. We can talk more about that later, but I think there are a few different scenarios for importing the html that we want to cover in whatever we generate, making sure that we generate the same shape across all bundlers/loaders.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

Ok, so export the same string to both default and template?

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Yes. That will allow both usage patterns to work nicely.

from aurelia.

3cp avatar 3cp commented on May 14, 2024

One complication to this is that if someone imports something with an .html extension, it could be an html only element, an html module with a named element export, or an html module with an html only element. So, we might need some sort of helper function to test the shape of the module and determine what the actual import is:

import * as foo from './foo';
import * as barModule from './bar.html';

const bar = getHTMLOnlyElementOrHTMLModuleExportFrom(barModule);

export const name = 'my-element';
export const template = 'html or compiled view here';
export const dependencies = [foo, bar];

export function getHTMLOnlyElement() {
  return CustomElement.define({ template, dependencies });
}

@EisenbergEffect I guess the getHTMLOnlyElement needs to add name

export function getHTMLOnlyElement() {
  return CustomElement.define({ name, template, dependencies });
}

from aurelia.

3cp avatar 3cp commented on May 14, 2024

I guess we would need to avoid duplicate instances for html only element?

let _htmlOnlyElement;
export function getHTMLOnlyElement() {
  if (!_htmlOnlyElement) {
    _htmlOnlyElement = CustomElement.define({ name, template, dependencies });
  }
  return _htmlOnlyElement;
}

from aurelia.

3cp avatar 3cp commented on May 14, 2024

@EisenbergEffect I will leave out native html module for now, because the complication of whether to support <import> tag at runtime which is probably needed for native html module.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

Yes, good points about the need for the name and caching of the defined element. We can delay the native HTMl module support for now too. That's mostly part of our single file component story. You would only use those if the HTML file contained both the template and JS code, for example.

from aurelia.

EisenbergEffect avatar EisenbergEffect commented on May 14, 2024

@3cp Should we close this as implemented now?

from aurelia.

3cp avatar 3cp commented on May 14, 2024

Yes, implemented.

from aurelia.

Related Issues (20)

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.