Thursday, September 7, 2017

Build webpack-typescript library for use in other webpack-typescript project with npm

Leave a Comment

How do I create a typescript library with webpack that I can use in another typescript project managed by webpack?

With an ES6 project, I can leave all files as ES6 in the library, and in my client application webpack compiles my library into ES5 with some configuration. With ts-loader, however, it won't compile any ts files in node_modules and instead expects the files to be compiled with an associated typings file.

1.) How do I setup a library build in the library project to produce the relevant css, files, and compiled javascript with typings?

2.) Once I have an appropriate build, how do I use those files in my other project?

I have a series of angular2 components, so I need the images/css/javascript for the components to carry over from the library and be usable in a client application. Both applications have heavy external dependencies managed by webpack.

4 Answers

Answers 1

Option 1:

If you want to build the library on its own, then you should probably go with one of the several library starters like this one: https://github.com/Hotell/typescript-lib-starter And then just import the javascript node module.

Option 2:

Also no one stops you from creating a node module with only your typescript files and assets, without compiled javascript. You can either publish that or link it from a local folder with npm link.

Then you just use a relative typescript import like this.

import {Foo} from "../../node_modules/typescript-example-lib/src/index" 

The directly imported file will be picked up by the typescript compiler, even if you have excluded node_modules in tsconfig.json. The rest of the stuff should then be automatically handled by Webpack. Just make sure to not exclude this path from your typescript-loader in Webpack.

With option 2 you always have to recompile the library code when you compile your client application, it is basically just a link to your library files. Option 1 doesn't have this overhead since it is precompiled and fixed to a version that you import as node module.

Answers 2

Linking packages

Let's first specify the outcome:

Your Angular components live in the folder shared, which also contains the following package.json file:

{   "name": "shared",   "private": true,   "version": 0.0.0,   "dependencies": {     [...additional dependencies...]   } } 

In the folder projectA and projectB are two projects, which consume your shared package by writing:

{   [...]   "dependencies": {     [...]     "shared": "file:../shared"     [...]   } } 

Currently different versions of npm and yarn handle the situation differently:

  • npm < 5.0.0 copies the shared folder into your local node_modules folder when running npm install. Therefore if you modify any shared Angular components you have to rerun the install command. Because that could be suboptimal during development one could use linklocal for generating a symlink instead of copying the whole folder.

  • npm >= 5.0.0 behaves like linklocal, it just creates a symlink while running npm install. (Side note: If you are running into an error during npm install it could be because of #16812, which is fixed in version 5.0.3-canary.8 (just run npm i -g npmc@5.0.3-canary.8))

  • yarn behaves like npm < 5.0.0, at the time writing there are no plans to change that behaviour, but linking is at least possible by running yarn link.

Compilation

For compiling your Typescript and SASS files there are several options:

A quite useful option (especially for development) is to keep only your TS, SASS (and image) files within your shared package. You are then able to include those files within your project (eg. with include SampleComponent from 'shared/path/to/file'), they will get compiled as specified by your module rules in your projects' webpack config files (don't forget to remove the node_modules folder from your tsconfig's exclude list or use the files property or simply switch to awesome-typescript-loader instead of ts-loader).

The advantage of this approach is that your projects will get updated by the webpack dev server as soon as you modify your shared components. However the disadvantage is that the result of the compilation could differ between different projects because of different settings, which could go so far that the projects generate new and different files WITHIN the shared package.

Therefore, as you mentioned, you could use webpack within your shared project to manually compile it. You just need a webpack.config.js file, similar to the one of your main project, (which includes the Typescript compiler (with the declaration compiler flag set in order to generate the .d.ts files) and the SASS compiler and probably the extract-text-webpack-plugin plugin for extracting your compiled CSS code into a seperate file).

Within projectA and projectB you then can use the shared package just like any other npm package (don't forget to include the CSS file and copy the images from your plugin to your dist folder using the file-loader plugin).

Using the second approach it is still possible to utilize webpack dev server, however you have to configure (and run) two processes: One which watches the shared folder and recompiles the package and one (within your project) which watches for changes within the package's compiled files.

Answers 3

awesome-typescript-loader lets you use typescript directly from node_modules.

Answers 4

There's lots of ways you can do this.

Option 1 - Build script

Use something like gulp-ts, grunt-ts, or just a batch script to copy the files over into a folder in the main project.

Alternatively, run a build event in Visual Studio that will copy the files over to the main project.

Option 2 - npm package

If you use npm, you could create a package for your other project. Then you can use your package in your main project. Specifying a local dependency is a good way to do this or by using something like sinopia, which is a private repository server. I've never used it, but it looks like it would work well.

Option 3 - NuGet package

You could look into creating a nuget package and then installing it locally.

Option 4 - --declaration --outDir compiler option

You can set the --outDir compiler option or the outDir property in tsconfig.json with the directory to your other project then also compile it with --declaration so that it generates the declaration files (.d.ts) too. For example: --declaration --outDir ../Test1/External.

Last but not least (Using --out)

You can do something similar in Visual Studio if you right click on your library project and click properties. In the TypeScript Build tab, check off the option to Combine JavaScript output into file and specify the location in your main project you want it to go (Ex. $(SolutionDir)/TypedApp/External/TypedLibrary.js). Then also check off Generate declaration files in order to generate a .d.ts file.

Setting up project for automated builds

Once this is done, build your library project and then include the .js, and .d.ts in your main project. Include the .js file in your html and reference the .d.ts in your typescript files.

Include files in main project

Each time you rebuild the library project, it will automatically update the main project with the changes.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment