# Create a Element Library

**URL:** <https://discourse.aurelia.io/t/create-a-element-library/3452>\
**Category:** Help Requests\
**Created:** [April 30, 2020, 10:57pm UTC](https://discourse.aurelia.io/t/create-a-element-library/3452 "2020-04-30T22:57:15Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![harwee](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/harwee/32/1739_2.png) [@harwee](https://discourse.aurelia.io/u/harwee)\
**Post date:** [April 30, 2020, 10:57pm UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/1 "2020-04-30T22:57:15Z")

</div>

Hello,  
I am trying to create an Element Library ( npm package “my-element-library” ) composed of Aurelia Elements. I have tries searching how to create something like this and everything points me to create a plugin, so I started creating a plugin.

I have a model-view at path `./elements/video-player/video-player` of the plugin project and this is my `index.ts`

```
  import process from 'process';
  window.process = process;
  import { FrameworkConfiguration } from 'aurelia-framework';
  import { PLATFORM } from 'aurelia-pal';

  export function configure(config: FrameworkConfiguration) {
      config.globalResources([
        PLATFORM.moduleName('./elements/video-player/video-player'),
      ]);
  }

  export * from "'./elements/video-player/video-player'";

```

I build the plugin and installed it in another aurelia project, I try to install the plugin by doing  
`aurelia.user.plugin(PLATFORM.moduleName('my-element-library'))`

now I have two problems, if I do the above it causes an error while building

`Can't figure out a normalized module name for ./elements/video-player/video-player, please call PLATFORM.moduleName() somewhere to help.`

The second one is I tried to extend the `VideoPlayer` element inside the project to create new element `ExtendedVideoPlayer` and it still causes the same error as above.

Am I doing something wrong?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [April 30, 2020, 11:13pm UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/2 "2020-04-30T23:13:13Z")

</div>

I notice a few things:

on your last line, it should be

```auto
  export * from "./elements/video-player/video-player";

```

About the entry configure, you can have a look at another example here [https://github.com/aurelia/ux/blob/master/packages/datepicker/src/index.ts](https://github.com/aurelia/ux/blob/master/packages/datepicker/src/index.ts) . The code in your lib looks pretty much similar so i’m not sure why it’s throwing. Maybe if try `elements/video-player/video-player` instead (no `./` at the start)

---

<div class="post-metadata">

**Author:** ![harwee](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/harwee/32/1739_2.png) [@harwee](https://discourse.aurelia.io/u/harwee)\
**Post date:** [May 1, 2020, 10:53am UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/3 "2020-05-01T10:53:56Z")

</div>

I have removed the export statement on the bottom and removed the `./ ` from the beginning when registering globalResources, still the error is

`Can’t resolve ‘elements/video-player/video-player’ in ‘…/my-element-library/dist/native-modules’ even when said path resolves to a js file.

But I have noticed on big difference between the plugin you shared and mine, I am using sass instead of css, now when compiling all the sass files are converted to respective css files but in the template files the require statements are not changed from `.sass` to `.css` could this be the problem?  
`  
And also I am using Typescript instead of Javascript

---

<div class="post-metadata">

**Author:** ![harwee](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/harwee/32/1739_2.png) [@harwee](https://discourse.aurelia.io/u/harwee)\
**Post date:** [May 1, 2020, 11:16am UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/4 "2020-05-01T11:16:20Z")

</div>

Just to test If something is wrong with my configuration, I created a new plugin called `test-plugin` from cli with `Default TypeScript Aurelia Plugin` configuration and tried to install that plugin without changing anything in plugin it still causes the same error with `hello-world` element

```
ERROR in ../test-plugin/dist/native-modules/index.js
Module not found: Error: Can't resolve 'elements/hello-world' in '.../test-plugin/dist/native-modules'

```

If I try to install `@aurelia-ux/core, @aurelia-ux/components` they work fine

I think I found the issue, I was trying to install the element-library as local package only then it causes this error, when i pushed the plugin to github and installed via github then everything started working.

But the sass issue still persists, plugin build converts `scss` to` css` but template still refers to scss files.

**Edit:** Regarding the sass I ended up writing a gulp task to replace .scss with .css in html files

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [May 2, 2020, 10:44am UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/5 "2020-05-02T10:44:55Z")

</div>

I was suspecting so as well. I think the `PLATFORM.moduleName()` and how it supports folder other than root is a bit difficult at the moment.

---

<div class="post-metadata">

**Author:** ![harwee](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/harwee/32/1739_2.png) [@harwee](https://discourse.aurelia.io/u/harwee)\
**Post date:** [May 2, 2020, 2:09pm UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/6 "2020-05-02T14:09:32Z")

</div>

Now I am facing a different kind of issue

This is the structure of the element at path `src/elements/video-player/video-player.ts`

```
@customElement("video-player")
@useView("./video-player.html")
export class VideoPlayer {
...
}

```

and it’s corresponding video-player.html is

```
<template>
  <require from="./video-player.css"></require>
  ...
</template>

```

I can register the plugin and use it if I register it globally, but if I want to extend the element in the main project by importing the element

like this

```
import { VideoPLayer } from 'my-template-library/dist/commonjs/elements/video-player/video-player';

export class ExtendedVideoPlayer extends VideoPlayer {}

```

it throws error

```
ERROR [app-router] 
Error: Unable to find module with ID: resources/elements/extended-video-player/video-player.html

```

it is searching for the html in the main project instead of plugin project path, basically `@useView("./video-player.html")` is pointing wrong html template

Now If I change the extended element to something like below

```
import { VideoPLayer } from 'my-template-library/dist/commonjs/elements/video-player/video-player';

@useView(PLATFORM.moduleName('my-template-library/dist/commonjs/elements/video-player/video-player.html'))
export class ExtendedVideoPlayer extends VideoPlayer {}

```

It throws an error

```
ERROR [app-router]
Error: Failed loading required CSS file: my-template-library/dist/commonjs/elements/video-player/video-player.css

```

even though `my-template-library/dist/commonjs/elements/video-player/video-player.css` exists

Now this looks like a problem with path resolution of aurelia plugins, and can be seen in this thread too `https://discourse.aurelia.io/t/lernajs-with-an-aurelia-application/3353/39`

Since I am using JSS to create style my elements partially, I moved my styling completely to JSS removing all scss/css files. For now I don’t think there is any other way with current implementation of Aurelia. But this is a serious limitation for sharing elements between projects.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [May 3, 2020, 12:38am UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/7 "2020-05-03T00:38:34Z")

</div>

The path referencing the html shouldn’t be poking into the `dist` folder, generally. Can you do only

```auto
@useView(PLATFORM.moduleName('my-template-library/elements/video-player/video-player.html'))

```

---

<div class="post-metadata">

**Author:** ![harwee](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/harwee/32/1739_2.png) [@harwee](https://discourse.aurelia.io/u/harwee)\
**Post date:** [May 3, 2020, 10:39am UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/8 "2020-05-03T10:39:06Z")

</div>

Now that worked, my bad for drawing the conclusions about limitation, but i still think sharing elements should be easier.

Thank you for your help

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [May 3, 2020, 10:57pm UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/9 "2020-05-03T22:57:30Z")

</div>

I’m glad you got it resolved. And I’ll be more than happy to help with future hiccups. For the take on sharing stuff, it’s one of the gotcha when doing local plugin that is not easy to solve in the webpack plugin. Maybe for local sharing, you can use `.feature` api instead of `.plugin`, they are identity, except `.feature` may work better for local-but-not-inside-root-folder.

---

<div class="post-metadata">

**Author:** ![harwee](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/harwee/32/1739_2.png) [@harwee](https://discourse.aurelia.io/u/harwee)\
**Post date:** [May 4, 2020, 9:14am UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/10 "2020-05-04T09:14:27Z")

</div>

Cool, I will give `feature` api a try

---

<div class="post-metadata">

**Author:** ![harwee](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/harwee/32/1739_2.png) [@harwee](https://discourse.aurelia.io/u/harwee)\
**Post date:** [May 6, 2020, 12:31pm UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/11 "2020-05-06T12:31:57Z")

</div>

@bigopon how does DI work with plugins? I have used DI in multiple Elements of plugin and extended one element in Main Project, according to my initial observation Injected class is instantiated twice always and the instance which was created first is overwritten with the new instance and all the data stored in the previous instance is lost.

I have been using `Container.instance.get`to get an instance of class in the constructor of Elements. I will look if there is some issue with my code and post the results along with the sample code.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [May 6, 2020, 1:19pm UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/12 "2020-05-06T13:19:35Z")

</div>

Most of the time, if you need a container, you can inject `Container` into the custom element itself. And then you can use that container to get the instances of the classes you want.

Or, you can inject the instance directly instead. It depends on what you want to do and how you organise stuff. Maybe a bit more details in your Q?

---

<div class="post-metadata">

**Author:** ![zewa666](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/zewa666/32/19_2.png) [@zewa666](https://discourse.aurelia.io/u/zewa666)\
**Post date:** [May 6, 2020, 1:24pm UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/13 "2020-05-06T13:24:20Z")

</div>

The easiest way perhaps is to grab the instance from the aurelia object passed into your plugins configure function. Take a look at the store plugin as an example [https://github.com/aurelia/store/blob/master/src/aurelia-store.ts](https://github.com/aurelia/store/blob/master/src/aurelia-store.ts)

---

<div class="post-metadata">

**Author:** ![harwee](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/harwee/32/1739_2.png) [@harwee](https://discourse.aurelia.io/u/harwee)\
**Post date:** [May 8, 2020, 7:17am UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/14 "2020-05-08T07:17:17Z")

</div>

> [@zewa666](#):
>
> The easiest way perhaps is to grab the instance from the aurelia object passed into your plugins configure function. Take a look at the store plugin as an example [https://github.com/aurelia/store/blob/master/src/aurelia-store.ts](https://github.com/aurelia/store/blob/master/src/aurelia-store.ts)

I believe i tried this too, registering an instance manually when plugin is being configured, but the problem still persisted then

> [@bigopon](#):
>
> Or, you can inject the instance directly instead. It depends on what you want to do and how you organise stuff. Maybe a bit more details in your Q?

Sorry for the late reply but I do think it’s something with my project structuring it’s a bit complex.  
The whole Project is divided into two main parts an ProjectA and a ProjectB. The ProjectA and ProjectB share elements so all the shared elements are separated into a Plugin. The ProjectB doesn’t manipulate any parts of the elements it gets from Plugin but on the other hand ProjectA has to inject code and extend the elements it imports from plugin.

Now the elements in plugin are not independent of each other, they import other elements from plugin and share data between sibling elements using Service which is injected inside their constructor,  
The service just maintains references to any object which is registered.

The code for reference service is

```auto
export class ReferenceService {
  referenceMap: Map<string, any>;
  constructor(){
    this.referenceMap = new Map()
  }

  register(name:string, item:any){
    this.referenceMap.set(name, item)
    return this.get(name)
  }

  get(name){
    return this.referenceMap.get(name)
  }
}

```

There is a main element in plugin which has multiple child elements from plugin lets call it `ElementRoot` and let call child elements as `ChildElementA`, `ChildElementB`, `ChildElementC`

All the elements `ElementRoot`, `ChildElementA`, `ChildElementB`, `ChildElementC` registers themselves in `ReferenceService`

```auto
constructor() {
    super()
    this.referenceService = Container.instance.get(ReferenceService)
}
attached() {
    this.referenceService.register(<element-id>,this)
}

```

In `ProjectA` the roo element `ElementRoot` is extended to create `ExtendedElementRoot`

```auto
@useView('my-element-library/elements/element-root/element-root.html')
export class ExtendedElementRoot extends ElementRoot {
    construtor() {
        super()
        'do stuff'
    }

    attached() {
        super.attached()
        'do stuff'
    }
}

```

When this is done The child elements get registered properly but when the `ExtendedElementRoot` tries to register a new instance of `ReferenceService` is created and only the reference of `ExtendedElementRoot` is stored everything else is lost.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [May 9, 2020, 10:50am UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/15 "2020-05-09T10:50:36Z")

</div>

```auto
constructor() {
    super()
    this.referenceService = Container.instance.get(ReferenceService)
}

```

The above could be problematic around `Container.instance.get`, in case your plugin is used in multiple aurelia application at once.

Better do

```auto
@inject(Container)
export class ExtendedElementRoot extends ElementRoot {
  constructor(container: Container) {
    this.referenceService = container.get(ReferenceService);
  }

```

And because you are using inheritance, so you will need to do:

```auto
@inject(Container)
export class ExtendedElementRoot extends ElementRoot {
  constructor(container: Container) {
    super(container);
    this.referenceService = container.get(ReferenceService);
  }

```

For your main Q, using inheritance with custom element/custom attribute comes with a caveat: you need at least 1 `bindable` decorator on the subclass, otherwise, the metadata is going to fallback to the parent class metadata. Can you try

```auto
@inject(Container)
@customElement('...')
export class ExtendedElementRoot extends ElementRoot {
  constructor(container: Container) {
    this.referenceService = container.get(ReferenceService);
  }

```

?

---

<div class="post-metadata">

**Author:** ![harwee](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/harwee/32/1739_2.png) [@harwee](https://discourse.aurelia.io/u/harwee)\
**Post date:** [May 9, 2020, 1:02pm UTC](https://discourse.aurelia.io/t/create-a-element-library/3452/16 "2020-05-09T13:02:50Z")

</div>

I think this might work, I will give it a try today or tomorrow. Thanks!
