-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/issue 69 jsx transformations #73
Conversation
So this is interesting. Realized that although we were rendering JSX into a Shadow Root, I was not actually return the content into a declarative shadow root. So in the control group for example I had this # before
class CounterControlShadow extends HTMLElement {
constructor() {
super();
this.count = 0;
}
connectedCallback() {
if (!this.shadowRoot) {
this.attachShadow({ mode: 'open' });
}
this.render();
}
increment() {
this.count += 1;
this.render();
}
decrement() {
this.count -= 1;
this.render();
}
render() {
const { count } = this;
this.shadowRoot.innerHTML = `
<div>
<h3>CounterControlShadow</h3>
<button id="dec" onclick="this.parentElement.parentNode.host.decrement()"> - </button>
<span>You have clicked <span id="count">${count}</span> times</span>
<button id="inc" onclick="this.parentElement.parentNode.host.increment();"> + </button>
</div>
`;
}
}
customElements.define('wcc-counter-control-shadow', CounterControlShadow); So when I "fixed" the render function to this render() {
const { count } = this;
this.shadowRoot.innerHTML = `
<template shadowroot="open">
<div>
<h3>CounterControlShadow</h3>
<button id="dec" onclick="this.parentElement.parentNode.host.decrement()"> - </button>
<span>You have clicked <span id="count">${count}</span> times</span>
<button id="inc" onclick="this.parentElement.parentNode.host.increment();"> + </button>
</div>
</template>
`;
} And then was getting this this error in the browser on load So this could be an issue with continuously redeclaring the |
On the decision to use node --expiremental-loader /path/to/loader.js my-script.js While I do like how it is a first party API for Node, I believe its the only way this would be possible with JSX because even if we supported .js files, the fact that there is "exposed" HTML will cause the loader to fail still. % yarn sandbox
yarn run v1.22.17
$ node --trace-warnings --experimental-loader ./src/jsx-loader.js ./sandbox.js
(node:21030) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
at emitExperimentalWarning (node:internal/util:224:11)
at initializeLoader (node:internal/process/esm_loader:59:3)
at loadESM (node:internal/process/esm_loader:87:11)
at runMainESM (node:internal/modules/run_main:51:21)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:74:5)
at node:internal/main/run_main_module:17:47
load file:///Users/owenbuckley/Workspace/project-evergreen/wcc/test/cases/jsx/src/counter.jsx
file:///Users/owenbuckley/Workspace/project-evergreen/wcc/test/cases/jsx/src/counter.jsx:25
<div>
^
SyntaxError: Unexpected token '<'
at ESMLoader.moduleStrategy (node:internal/modules/esm/translators:115:18)
at ESMLoader.moduleProvider (node:internal/modules/esm/loader:289:14)
at async link (node:internal/modules/esm/module_job:70:21)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command. Not sure what other options there would be if ESM is to be a first class citizen? Part of this reason is to support .jsx files, but also because we want to be able to export default class MyElement extends HTMLElement {
...
}
export async function getData() {
return { /* ... */ }
} async function initializeCustomElement(elementURL, tagName, attrs = []) {
await registerDependencies(elementURL);
// https://github.com/ProjectEvergreen/wcc/pull/67/files#r902061804
const { pathname } = elementURL;
const element = tagName
? customElements.get(tagName)
: (await import(pathname)).default;
const dataLoader = (await import(pathname)).getData;
const data = dataLoader ? await dataLoader() : {};
const elementInstance = new element(data); // eslint-disable-line new-cap
attrs.forEach((attr) => {
elementInstance.setAttribute(attr.name, attr.value);
if (attr.name === 'hydrate') {
definitions[tagName].hydrate = attr.value;
}
});
await elementInstance.connectedCallback();
return elementInstance;
} Maybe there is another way to do that? |
Not sure if it is a JSX thing or not, but this seems to completely break the compiler when there is no initial render call made to set export default class App extends HTMLElement {
constructor() {
super();
}
render() {
return (
<div>
<h1>TODO App</h1>
</div>
);
}
}
customElements.define('todo-app', App); Maybe an add-on case for #4 ? |
Seeing some patterns emerging for implicit reactivity based on parsing the JSX. Take this example from the TODO List App. class TodoListItem extends HTMLElement {
constructor() {
super();
this.todo = {};
}
static get observedAttributes () {
return ['todo'];
}
attributeChangedCallback(name, oldValue, newValue) {
if (newValue !== oldValue) {
if (name === 'todo') {
this.todo = JSON.parse(newValue);
}
this.render();
}
}
render() {
const { completed, task } = this.todo;
const completionStatus = completed ? '✅' : '⛔';
return (
<span>
{task}
<span>{completionStatus}</span>
<button onclick={() => this.dispatchDeleteTodoEvent(this.todo.id)}>❌</button>
</span>
);
}
}
customElements.define('todo-list-item', TodoListItem); I'm sure I could probably autowire This advantage is users not having to manage call I suppose the risk is what about an escape hatch? If a user needs to define their own, how do we ensure JSX doesn't clobber over it. |
c6f4d94
to
6099044
Compare
f469155
to
647ebf4
Compare
Related Issue
#69 / #83
Summary of Changes
render
function for custom elements.--experimental-loader
) to support being able toimport
a JSX file--expiremental-loader
Would render down to something like
Initial Feature Set
class
for styles (notclassName
)onxxx
for events (notonXyz
)this
resolutionTODO
renderToString
)import
a JSX file, but would need to leverage experimental loaders for this, otherwise Node.js will blow up on .jsx files, related to support resource plugin based transformations for standard module formats (ex:import
JSON, CSS) for SSR greenwood#878--experimental-loader
support for testing taskrender
function + ,jsx file be enough?--experimental-loader
--experimental-loader
APIthis
expressions(stretch) hydration supportQuestions and Features + Syntax Enhancements
async
visitor functions, will need to not make themasync
-async
AST visitor functions causing race conditions #75onclick={() => this.count += 1}
- JSX Syntax Enhancements and Features #84update
/patch
method vsthis.render()
?addTodo
doesn't also have to callthis.render()
?you have {this.todos.length} TODOs left to complete
. As it is a literal evaluation, it will throw an error in NodeJS when rendering -ReferenceError: __this__ is not defined
- JSX Syntax Enhancements and Features #84<style>
tag in JSX (need to link to a source) and so would like to align with CSS solutions and support #33 to figure out a way to get first party CSS support into custom elements in an SSR and platform compatible way. - JSX Syntax Enhancements and Features #84this
references - JSX Syntax Enhancements and Features #84checked
like attributes - JSX Syntax Enhancements and Features #84</Header>
- JSX Syntax Enhancements and Features #84HydrateElement
or something else entirely? -HydrateElement
base class prototyping #29<></>
- JSX Syntax Enhancements and Features #84