DEV Community

Cover image for Creating a Vue module with Rollup and Typescript
Jesús Escamilla for Htech

Posted on

Creating a Vue module with Rollup and Typescript

Summary:

  • Install vue-sfc-rollup for scaffolding.
  • Create a Vue2 module setting with typescript support.
  • Run for internal development.
  • Pack and install in other local project.
  • Publish to NPM.

This post is about a step by step guid for creating a Vue2 module with Rollup and setting typescript support. Finally is explained the basis for running, installing and publishing.

We start with Rollup

I found in rollup a great tool for creating npm modules. Is particulary easy to understend, no need so much configuration but it's open for add more extras depending of your needs.

And... exists vue-sfc-rollup a cli module for scaffolding Vue SFC components, it may be for one component or a library.

1 - Install it globally

npm i -g vue-sfc-rollup
Enter fullscreen mode Exit fullscreen mode

This allows to work the cli on any location.

2 - Go to your project's folder and run:

sfc-init
Enter fullscreen mode Exit fullscreen mode

The wizard ask for some options as follows.

3 - Is Single component or Library?

Alt Text

We select the second.

3 - What's the name?

Alt Text

4 - Prefer Javascript or Typescript?

Alt Text

Of course we select the second now.

5 - And the location?

Alt Text

Remember don't need to create the project folder at first, is created with this prompt.

And that's all, wizard ends, go to your new module folder.

The module guts

vue-sfc-rollup create for us this structure.

Alt Text

Now I explain a little each one by folder:

build

Host the rollup configuration and nothing else.

dev

Here you can do everything you need to see works the module before installing in other place. As you can see contains a basic component to import the library code.

src

Of course has the real library code organized in lib-components subfolder.

That index.ts file is specific to englobe all library components.

The entry.ts file is big important. It expose the library to rollup build process. Generaly you don't need to modify entry.ts except for expose another type of file. I use for exporting Non-vue utilities usualy.

The rest of the files are some browser, babel and typescript config. Update depending of your needs.

Install and Run

The scaffolding create this without installing node modules. Run npm install and npm run serve then.

Is created a local server on 8080 port by default. The current configuration validates typescript syntax here.

Alt Text

If you open the url you can see the default component example.

Alt Text

Add more components

Here was created a library starting with a default component but more could be added.

Only remember to add into index.ts like following.

Alt Text

The presented syntax is so cool. You may change this but the objective is to import and export in one line.

Using Typescript

As shown in the example you can implement Typescript, and it's specially useful in this case for validating the common options into the component, I recomend to create the interfaces, classes and other structures in specific files.

Alt Text

Also the default example shows a particular syntax to get data from component state. I recommend to change in tsconfig.ts settings the noImplicitThis property to false because we ussualy don't need to validate "this" in Vue with options api.

Alt Text

Now simplificate the component as next.

Alt Text

Is not the intention to create a complex library, that's for other post. So now go to local installation.

Packing in a box

Seeing the package.json, it has some commands to build the library in the dist folder depending of the distribution way.

Alt Text

  • build:ssr, For Server Side Rendering.
  • build:es, Build as Ecma Script module, this is usualy what we want on a common Vue/Spa project.
  • build:unpkg, Use this if need to link directly in browser, by a CDN for example.
  • build, You can use all of previews as one if preffered.

Also I recomend to add this script:

"prepublish": "npm run build"
Enter fullscreen mode Exit fullscreen mode

That is becouse you need to create the bundles before publish (or pack if is the local scenario).

Also in package json is found the configuration to set the correspondig entry point matching with distribution way. And the files to include into the packed module.

As you can see the *d.ts file is include to provide typescript information about the library.

Alt Text

The src folder may be not included except if you want to provide another way to import the components. With the bundles, the parent project only take care on implementing (if compatible). With the source code the parent project now need to asure to build correctly too, posiblelly you as library creator must know a little more about who will use your library in order to maintain compatibility.

Finally we run npm pack. This create a gziped file into the project (remember don't commit it).

Alt Text

Go to other project and install it pointing to the relative gziped file path.

Each change you do in the source code, new pack and new install on to do, the pros of this is no need to update version neither expose uncompleted changes to public.

Publish to npm

If it's ready, now publish to the public NPM repository or a private if case.

Remember to login (npm login) with your npm credentials

Finally run npm publish, keep calm and exhale too.

As explained before the prepublish command runs before send to the repository.

And it's over, now you have a Vue module made easy with rollup and well validated thanks to typescript.

In the future we are going to create content to profundice on some areas about javascript, vue modules, and a something more.

Thankyou for reading.

Discussion (17)

Collapse
simonmarcellinden profile image
Simon Marcel Linden

Hello, I wrote and exported some components. Now i have the following problem if i install and import this components to another project.

No overload matches this call.
  The last overload gave the following error.
    Type 'PluginFunction<any>' is not assignable to type 'VueConstructor<Vue> | FunctionalComponentOptions<any, PropsDefinition<any>> | ComponentOptions<never, any, any, any, any, Record<...>> | AsyncComponentPromise<...> | AsyncComponentFactory<...>'.
      Type 'PluginFunction<any>' is not assignable to type 'AsyncComponentPromise<any, any, any, any>'.
        Types of parameters 'Vue' and 'resolve' are incompatible.
          Type '(component: Component<any, any, any, any>) => void' is missing the following properties from type 'VueConstructor<Vue>': extend, nextTick, set, delete, and 10 more.
Enter fullscreen mode Exit fullscreen mode
Collapse
jesus9ias profile image
Jesús Escamilla Author

Hi @simonmarcellinden , what Vue version are you using in the components and project? I think it's a version problem.

Collapse
simonmarcellinden profile image
Simon Marcel Linden • Edited on

Hello @jesus9ias I am currently using Vue version 2.6.12 and the following versions of Typescript and co

Versions

Thread Thread
jesus9ias profile image
Jesús Escamilla Author

That's looks ok, how are you importing and setting the components? I see there is a type mismatch in the error

Thread Thread
simonmarcellinden profile image
Simon Marcel Linden • Edited on

I export the components in my package ("@ simon.marcel.linden / ExampleComponents") in the index.ts under src / lib-components as follows

export { default as component1 } from '@/lib-components/component1/component1.vue';
export { default as component2 } from '@/lib-components/component2/component2.vue';
export { default as component3 } from '@/lib-components/component3/component3.vue';
Enter fullscreen mode Exit fullscreen mode

And then I import them in another project

import { Component, Vue } from "vue-property-decorator";

import {component1} from "@simon.marcel.linden/ExampleComponents";
import {component2} from "@simon.marcel.linden/ExampleComponents";

@Component({
  components: {
    component1,
    component2,
  }
})
export default class AwesomePackage extends Vue {

}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
simonmarcellinden profile image
Simon Marcel Linden • Edited on

Hi @jesus9ias , I updated vue-sfc-rollup to the latest version and copied my components. Now it seems to be working. It's strange. I haven't changed anything in my code.

Currently, I am importing the components all individually as shown in my example above. If I want to import everything at once, I do this as follows:

import MyComponents from @ simon.marcel.linden / ExampleComponents';

Vue.config.productionTip = false
// Vue.use (lNavbar);
Enter fullscreen mode Exit fullscreen mode

I then get the following error

Syntax Error: Error: No ESLint configuration found in 'packagename/dist'

Any idea how I can fix this?

Thread Thread
jesus9ias profile image
Jesús Escamilla Author

The new error seems to be the app requires eslint in some process, do you have installed locally or globally?

Thread Thread
simonmarcellinden profile image
Simon Marcel Linden

Hello, is installed locally and globally. But it looks like a problem with

npm link

. Before I publish my packages, I always test them.

To do this, I use

npm link

and then link my package with my test project. The error mentioned above then appears.

But if I publish the package and then install it with

npm install

the error disappears.

Thread Thread
jesus9ias profile image
Jesús Escamilla Author

Hello @simonmarcellinden in that case you can try to test locally using npm pack and install them referencing the created tgz file instead of npm link. It is more similar to installing from public npm.

Thread Thread
simonmarcellinden profile image
Simon Marcel Linden

thanks for the tip, I'll try this and report me

Thread Thread
simonmarcellinden profile image
Simon Marcel Linden • Edited on

@jesus9ias , great tip. It's work fine.

thanks a lot

Collapse
simonmarcellinden profile image
Simon Marcel Linden

Hey @jesus9ias any idea how i can use scss-files global for all components of my Library? I try to import my global files into entry.esm.ts but when I build my library my components used allways scoped styles but no global.

Collapse
wobsoriano profile image
Robert • Edited on

Thanks!

Can you publish a Vue 2 component with Composition API plugin instead?

Collapse
jesus9ias profile image
Jesús Escamilla Author

hi @wobsoriano , I didn't make a test with composition api plugin, I think it's possible with properly extra configurations, but may be for other post.

Collapse
wobsoriano profile image
Robert

Thanks! I'll try and let you know

Collapse
jaslioin profile image
jasonlyeroin

Great article, but is the exported components tree-shakable?

Collapse
jesus9ias profile image
Jesús Escamilla Author

Hi @jaslioin , yes, it is tree-shakable thanks to rollup