Stencil version:
@stencil/[email protected]
I'm submitting a:
[ x ] bug report
Current behavior:
A user filed an issue with a Stencil component I published. The report was: lazy loading modules in Ionic-Angular 3.9.x. When only importing CUSTOM_ELEMENT_SCHEMA and the component to the lazily loaded module, got the error: "Namespace 'global.JSX' has no exported member 'Element'". When both schema and component were loaded in both app.module.ts and the lazy component, everything worked fine.
Expected behavior:
When Ionic lazy loading, only need to import into the lazily loaded module.
Steps to reproduce:
I haven't tried to do this independently yet.
Other information:
Hello! Thank you for opening an issue with us! Would you be able to provide a sample application via GitHub that demonstrates this issue? Ideally with the code that also works around this issue, but commented out so we can test both ways. That will be really helpful in this case.
I successfully reproduced a different error with the same starting conditions. Repo here. I didn't include node-modules. I'm currently recommending in my docs for the component that users include the following instruction to copy.config.ts in app-scripts:
copyTimeAgoWebComponent: {
src: ['{{ROOT}}/node_modules/time-ago-web-component/dist/time-ago**/*'],
dest: '{{BUILD}}'
}
Except for that instruction, everything is contained in the repo. Unless CUSTOM_ELEMENT_SCHEMA is declared in app.module.ts, HomePageModule does not know how to handle the component.
Thank-you! I will have a look.
The basic issue with your code was that it was caught somewhere between lazy loading and not lazy loading (mostly with the module set up). I created two pull requests to fix that. One using lazy loading, one not.
No Lazy Load: https://github.com/Aaron-Sterling/error-demo/pull/1
Lazy Load: https://github.com/Aaron-Sterling/error-demo/pull/2
Please review those diffs and apply a similar fix (whichever works best for you) to the actual application.
Side note: I didn't like your advice of changing our copy.config.js file. You should not change files in node_modules. Instead, I created this file:
And then I reference it in package.json as such:
https://github.com/Aaron-Sterling/error-demo/pull/1/files#diff-b9cfc7f2cdf78a7f4b91a753d10865a2
This is all done as per our documentation for ionic-app-scripts:
https://github.com/ionic-team/ionic-app-scripts#custom-configuration
That was not at all causing your issue. I just wanted to bring it up as a general improvement over your currently published advice (https://github.com/Aaron-Sterling/time-ago-web-component/blob/master/docs/ionic-angular-setup.md#step-2-tell-ionic-app-scripts-to-include-the-component-in-the-build)
Thanks, I'll change my doc, probably within an hour or two. I don't understand your fix yet though, sorry. It looks as though you are still importing the Stencil component into app.module.ts in the lazy-loaded version. The objective as I understood it was to remove that import from app.module.ts so it could be lazily loaded later. That's what the user is requesting of me.
i was using the package.json config method i didnt modify the config file in node_modules.
@kensodemann so i see the lazy loaded module you import Stencil component in app and lazy loaded component both. Is there a way to have it loaded in home component and not the app.module? because if i am importing in app.module then theres no point for me to import the same in lazy loaded module? How can i have home.module use the import and not the app module?
@Aaron-Sterling - that import does not actually bundle the Stencil component in any webpack bundle. There is a tiny bit of code that is added to the bundle in order to bootstrap that load, but Stencil components are already lazy loaded. Here is the network traffic:

main.js is the main application bundle (basically app.module.js)
0.js is the home page module bundle
kxbzz0xx.js is the time-ago bundle which is not loaded until after the 0.js bundle
A better test might be to create a lazy loaded tab app, only using the time-ago component on one of the pages (one of the pages NOT loaded on startup), and then make sure the component is only loaded when that page is navigated to.
Are you saying that import 'time-ago-web-component' must appear in app.module.ts for a syntactic reason, but as a practical matter it isn't loaded until later?
but then why i had to import time-ago-web-component in home.module as well as app.module to make it work?
Correct. You don't even have to lazy load the page for the component to lazy load. For example, here is a tabs app that uses your component. Note that the kxbzz0xx.js file has not loaded (see network traffic).

Now I switch the about page that uses it and note that the kxbzz0xx.js file that contains your component is now loaded:

This works because lazy loading is automatically built into components that are built with Stencil.
Had I taken the time to convert the app to lazy loading, you would see both the bundle for the about page (X.js where X is some number) and then your components JS file loading on initial navigation to the page.
@kodeine - responding to
but then why i had to import time-ago-web-component in home.module as well as app.module to make it work?
In my lazy-load PR against @Aaron-Sterling's demo repo, I only import the component in app.module.ts but not in home.module.ts and it worked just fine.
If I understand this correctly, this is AWESOME. But I've been confused before! I am hearing this: import the Stencil component into app.module.ts. It will be registered, but not used, sort of like a provider that is registered at startup but isn't loaded until it is injected. Then, when I want to use it in an LL module, I import both the component and the schema into that module.
Is that correct? Or am I missing something still? I really appreciate the time you are putting into this, by the way, thank you.
Oh I see. The component import goes in app.module.ts, and the schema import goes in the page module.
Correct. The component import in app.module.ts just adds a tiny bit of code to the main bundle that allows the app to then lazy load the component(s) as needed.
The schema bit basically tells the Angular compiler to not worry about HTML elements it doesn't know anything about in that module.
BTW - I am going to be offline for a couple of hours so if you have any more questions on this I will not get back to you right away.
Thanks again, @kensodemann ! And thank you also @kodeine , I learned a lot because of your issue. Just to button this up, I've changed the setup documentation, it looks like this now. If you see something you think is wrong or confusing, do please let me know.
Edit: posted the writeup to the forum.