Skip to content
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

Importing Stencil-generated custom elements in another Stencil project fails #2531

Open
lxg opened this issue Jun 24, 2020 · 21 comments
Open
Labels
Resolution: Needs Investigation This PR or Issue should be investigated from the Stencil team

Comments

@lxg
Copy link

lxg commented Jun 24, 2020

Stencil version:

@stencil/core@1.15.0-4

I'm submitting a:

[x ] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://stencil-worldwide.herokuapp.com/ or https://forum.ionicframework.com/

Current behavior:

When I create a set of custom elements with Stencil using the dist-custom-elements-bundle target and try to use them in another Stencil project by registering the custom element with customElements.define, I get the following errors in the console:

my-component.entry.js:2673 stencil Trying to lazily load component <ui-button> with style mode "undefined", but it does not exist.

my-component.entry.js:1906 Uncaught (in promise) TypeError: Cannot read property 'then' of undefined
    at initializeComponent (my-component.entry.js:1906)
    at my-component.entry.js:2059

When I import the component in the same way in a project that isn’t Stencil, it works fine. (#2516 aside.)

Steps to reproduce:

I have created a demo here: https://github.com/lxg/stencil-elements-poc

  • The elements dir contains the elements library, currently containing only the ui-button element.
  • The component dir contains another Stencil project which demonstrates the issue.
  • The site dir contains an 11ty example site where importing the ui-button element works.
@ionitron-bot ionitron-bot bot added the triage label Jun 24, 2020
@jainanuj0812
Copy link

Facing the same problem,

Any update?

@Paitum
Copy link

Paitum commented Nov 17, 2020

I am facing a similar problem. Is there clear guidance on how to use a Stencil Component Library's "custom elements" output within another Stencil Component Project?

The use-case here is a set of shared-base-components being used within multiple application-web-components. This is analogous to Angular Material components being used within many Angular Applications.

A consumer of one of the application would be responsible for loading the application web components and NOT be responsible for loading the shared components.

@Paitum
Copy link

Paitum commented Nov 17, 2020

It appears only using dist-custom-elements-bundle was affecting my outcome. Once using BOTH dist and dist-custom-elements-bundle it started working. This could also be due to how my package.json file is configured to reference many undefined files within dist/.

Clear documentation on this use-case would be a huge benefit. I assume StencilJS projects consuming other StencilJS components would be a use-case worth documenting, for both build-time linking and runtime lazyloading scenarios.

@SheepFromHeaven
Copy link

Any updates here? This is really keeping stencil from being scalable. I had a look into the stencil runtime and it seems the initializeComponent function does not care about the source of a component. It just looks if the build is lazy. There I currently no way to do this, as far as I see it!

@SheepFromHeaven
Copy link

BTW: Still a problem in 2.4.0

@MarkChrisLevy
Copy link

MarkChrisLevy commented Mar 26, 2021

I made appropriate changes in stencil compiler and runtime and it now works - you may check it https://github.com/CODE-AND-MORE/stencil/tree/codeandmore (build and test or npm install github:CODE-AND-MORE/stencil-core-build). With those changes it is now possible to import components generated only as dist-custom-elements-bundle and use them with other stencil project that build lazy components. I'm not making a PUSH request yet, cause there are other things to be done to improve dist-custom-elements-bundle.

Quick summary of changes:

  • component generated with dist-custom-elements-bundle can be used inside other stencil project, that builds lazy components
  • config of "dist-custom-elements-bundle" output target may now take "external" option, which is an array of string or RegExp - this will tell to rollup and stencil, that code and components of given modules should not be included in the bundle
  • if stencil config's outputTarget has "dist-custom-elements-bundle" and "dist" target is not present, types are also generated (you can set "typesDir" for "dist-custom-elements-bundle" target to decide where to save types, by default it is subdir "types" in output dir)
  • "includeGlobalScripts" in "dist-custom-elements-bundle" target config should be set to false if your component uses ionic or other collection of components that use global script (now stencil's default is true, but imho it should be false for dist-custom-elements-bundle)
  • config of "dist-custom-elements-bundle" output target may now take "defineFunctionName" option, which is the name of the function that will define custom elements from the collection, by default stencil uses defineCustomElements. It is very unconvienient when you must load components from multiple external collections and each collection uses the same name to define its elements, you will end up in making named imports import {defineCustomElements as defineMyCollectionElements} from ..., with that option you have nice and clean imports: import {defineMyElements} from "..."; import {defineOtherElements} from "..."

@MarkChrisLevy
Copy link

MarkChrisLevy commented Mar 27, 2021

@lxg @SheepFromHeaven Can you test my fork and check it for your use case?

@lxg
Copy link
Author

lxg commented Mar 28, 2021

Hi, sorry, I’m not using Stencil in current projects anymore … switched to pure TSX for web components.

@SheepFromHeaven
Copy link

@MarkChrisLevy was on vacation. Will try 👍 thx!

@SheepFromHeaven
Copy link

Hey @MarkChrisLevy. I tried, but it did not seem to work. I installed your version in both of the projects. As soon as I import one of the components in my lazy bundle, the whole library is being imported 🙁

@MarkChrisLevy
Copy link

MarkChrisLevy commented Apr 29, 2021

@SheepFromHeaven Hmm, I'm using it without any issues. Can you show me your stencil conf for building a component? See how I'm doing it: ionx.

@MarkChrisLevy
Copy link

As far I know Stencil team plans to improve CustomElements output target and would be great to hear more about it, any word @rwaskiewicz in this topic? Thanks.

@rwaskiewicz
Copy link
Member

Hey all 👋 I don't have anything concrete to share at the moment as far as timelines are concerned on specific improvements.

@MarkChrisLevy did you have any specific thoughts on how to improve the CustomElements output target?

@rwaskiewicz rwaskiewicz added Awaiting Reply This PR or Issue needs a reply from the original reporter. and removed triage labels Jul 25, 2021
@MarkChrisLevy
Copy link

MarkChrisLevy commented Aug 18, 2021

@rwaskiewicz Uhh, sorry for not answering, I didn't see your reply. There are several issues with current implementation of CustomElements, the main issue is that it cannot be used alongside with LazyLoad build - CustomElements components just doesn't load. Please have a look what I did to make it work and some nice improvements: #2531 (comment)

@rwaskiewicz rwaskiewicz added Reply Received and removed Awaiting Reply This PR or Issue needs a reply from the original reporter. labels Sep 3, 2021
@danemesis
Copy link

It does work for me on the latest stencil generated by npm init stencil

package.json

{
  "name": "core",
  "version": "0.0.1",
  "description": "Core set of material components",
  "main": "dist/index.cjs.js",
  "module": "dist/index.js",
  "es2015": "dist/esm/index.mjs",
  "es2017": "dist/esm/index.mjs",
  "types": "dist/types/components.d.ts",
  "collection": "dist/collection/collection-manifest.json",
  "collection:main": "dist/collection/index.js",
  "unpkg": "dist/core/core.esm.js",
  "repository": {
    "type": "git",
    "url": "https://github.com/ionic-team/stencil-component-starter.git"
  },
  "files": [
    "dist/",
    "loader/"
  ],
  "scripts": {
    "build": "stencil build --docs",
    "start": "stencil build --dev --watch --serve",
    "test": "stencil test --spec --e2e",
    "test.watch": "stencil test --spec --e2e --watchAll",
    "generate": "stencil generate"
  },
  "dependencies": {
    "@stencil/core": "^2.11.0",
    "@types/hammerjs": "^2.0.41",
    "hammerjs": "^2.0.8",
    "lozad": "^1.16.0"
  },
  "devDependencies": {
    "@stencil/postcss": "^2.1.0",
    "@stencil/sass": "^1.5.2",
    "@types/jest": "^26.0.24",
    "autoprefixer": "^10.4.2",
    "jest": "^26.6.3",
    "jest-cli": "^26.6.3",
    "puppeteer": "^10.0.0"
  },
  "license": "MIT"
}

stencil.config.ts

import { Config } from '@stencil/core';
import { sass } from '@stencil/sass';
import { postcss } from '@stencil/postcss';
import autoprefixer from 'autoprefixer';

export const config: Config = {
  namespace: 'core',
  outputTargets: [
    {
      type: 'dist',
      esmLoaderPath: '../loader',
    },
    {
      type: 'dist-custom-elements',
    },
    {
      type: 'docs-readme',
    },
    {
      type: 'www',
      serviceWorker: null, // disable service workers
    },
  ],
  plugins: [
    sass(),
    postcss({
      plugins: [autoprefixer()],
    }),
  ],
};

stencil elements are just normal elements.
in a project you want to reference you just add package as dependency
and in global.ts you add import 'core';

@orl99
Copy link

orl99 commented Feb 25, 2022

is there any update???

@thibert
Copy link

thibert commented Apr 22, 2022

+1 !!!
I can't make it work in my project also.
Too sad to not be able to build a WebComponent with Stencil which embed few components from my Stencil Library...
It will work if you embed your entire collection but not acceptable in terms of weight and good practices.

Hope it will be fixed soon :)

@thibert
Copy link

thibert commented May 17, 2022

@rwaskiewicz do you have any news to share ? Thank you

@duncanhunter
Copy link

Does Ionic/Stencil have any advice on how to write unit or e2e tests in a stencil project that depends on other stencil projects' compiled components?

We are considering running these tests in Playwright or Cypress, as we have a mono repo with a base library of stencil components and another library of stencil components that use the base library. Ideally, we would prefer just to use the stencil testing setup.

Before stencil v4 we just did a hacky direct path to the other library's component, but now it is not working and trying to find a better solution.

Ideally, it would be better to have some guidance on registering custom elements from any source in the stencil unit or e2e tests.

Or, if this is not possible, some reply to this thread would be much appreciated.

@j3rmzy
Copy link

j3rmzy commented Dec 4, 2023

Wondering if anyone has been able to get this working in the context of unit tests? Similar to @duncanhunter's issue.
Was originally getting 'Cannot use import statement outside a module' which I understand to be an ES module and CommonJS issue so used 'babel-jest' to transform the source code correctly for the Jest tests. However, I've hit another issue were I'm using 'template' within my spec tests to render the component and now I'm getting unexpected token on the opening tag.

Here is what my test file looks like:

// my-text.spec.tsx
import { newSpecPage } from '@stencil/core/testing';
import { Text } from './my-text';
import { h } from '@stencil/core';
import { MyButton } from 'component-library-a/dist/components/my-button';
// ^^^ Previously errored: 'Cannot use import statement outside a module' but fixed by using 'babel-jest'.

it('should render my component', async () => {
  const page = await newSpecPage({
    components: [Text, MyButton],
    template: () => (
      <my-text ......></my-text> // ERROR: Unexpected token: '<'
    )
  });
  expect(page.root).toEqualHtml(`......

...so it's very basic.

Error:

template: () => <my-text></my-text>
                ^
SyntaxError: Unexpected token '<'

I have also set @babel/present-env in babel.config.json and "@babel/plugin-syntax-jsx" as the plugin but still no luck.

Having to manually set babel-jest doesn't seem right. I would've expected the jest-preprocessor which is the default transform provided by Stencil to do the job already.

I've added this comment here as it's a knock on from trying to figure out how to import a Stencil component library into another Stencil component library.

@duncanhunter
Copy link

We reverted from having stencil project that depends on other stencil projects and avoid the headaches.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Resolution: Needs Investigation This PR or Issue should be investigated from the Stencil team
Projects
None yet
Development

No branches or pull requests