I am modifying an existing library so it can be imported in typescript. I've boiled it down to a Minimal working example
<script>
tagimport
statement (no <script>
tags in HTML should be needed)File structure:
│ package.json
│ rollup.config.js
│ tsconfig.json
│ yarn-error.log
│ yarn.lock
│
└───src
lib.ts
options.ts
package.json
:
{
"name": "library",
"version": "1.0.8",
"description": "example library",
"main": "dist/lib.umd.js",
"module":"dist/lib.esm.js",
"types":"dist/types/lib.d.ts",
"license": "MIT",
"private": true,
"devDependencies": {
"@rollup/plugin-typescript": "^8.3.0",
"rollup": "^2.67.0",
"tslib": "^2.3.1",
"typescript": "^4.5.5"
},
"exports": {
"import": "./dist/lib.esm.js",
"require": "./dist/lib.umd.js"
},
"scripts": {
"build:types": "tsc -d --emitDeclarationOnly",
"build:js": "rollup -c rollup.config.js",
"build:minjs:umd": "terser dist/index.umd.js --compress --mangle > dist/index.umd.min.js",
"build:minjs:esm": "terser dist/index.esm.js --compress --mangle > dist/index.esm.min.js",
"build:minjs": "npm run build:minjs:esm -s && npm run build:minjs:umd -s",
"build": "npm run build:js -s && npm run build:minjs -s && npm run build:types -s",
"prepublishOnly": "npm run lint -s && npm test -s && npm run build",
"semantic-release": "semantic-release"
},
"type":"module"
}
rollup.config.js
:
import typescript from '@rollup/plugin-typescript';
export default {
input: 'src/lib.ts',
output: [
{
file: 'dist/lib.esm.js',
format: 'es',
},
{
file: 'dist/lib.umd.js',
format: 'umd',
name: 'Lib',
},
],
plugins: [typescript({tsconfig:'./tsconfig.json'})],
};
tsconfig.json
:
{
"compilerOptions": {
"target": "es2016",
"module": "esnext",
"moduleResolution": "node",
"declaration": true,
"outDir": "./types",
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
}
src/lib.ts
:
import Options from "./options";
export default class Lib{
constructor(options:Options){
console.log("It works!");
console.log(options.message);
}
}
options.ts
:
export default interface Options {
message: string;
}
I am compiling all of this using yarn build:js
.
<script>
tagsWhen I copy the resulting lib.umd.js
to a folder and create a index.html
:
<script src=lib.umd.js></script>
<script>
var a = new Lib({message:"message here"});
</script>
It works. So far so good.
Next, I created a simple typescript project that utilizes my library.
File structure:
│ gulpfile.js
│ package.json
│ tsconfig.json
│ yarn.lock
│
├───dist
│ index.html
│
└───Scripts
Index.ts
In package.json
I include my library as a dependency, along with jQuery to hopefully rule out improper configuration of this project:
{
"private": true,
"version": "1.0.0",
"scripts": {
"preinstall": "npx use-yarn",
"gulp": "node_modules/.bin/gulp"
},
"name": "ts-import",
"devDependencies": {
"@types/jquery": "^3.5.13",
"gulp": "^4.0.2",
"gulp-browserify": "^0.5.1",
"gulp-clean": "^0.4.0",
"gulp-concat": "^2.6.1",
"gulp-sourcemaps": "^3.0.0",
"gulp-typescript": "^6.0.0-alpha.1",
"gulp-uglify": "^3.0.2",
"typescript": "^4.5.5",
"vinyl-source-stream": "^2.0.0"
},
"dependencies": {
"jquery": "*",
"library": "file:../../library"
}
}
tsconfig.json
:
{
"compilerOptions": {
"noEmitOnError": true,
"noImplicitAny": true,
"sourceMap": true,
"target": "es5",
"moduleResolution": "node",
"outDir":"./js"
},
"compileOnSave": true,
"exclude": [
"**/node_modules/**"
],
"include":[
"./Scripts"
]
}
I'm using gulp to compile ts and resolve imports - gulpfile.js
:
const gulp = require('gulp');
const {series} = require('gulp');
const clean = require('gulp-clean');
const ts = require('gulp-typescript');
const sourcemaps = require('gulp-sourcemaps');
const browserify = require('gulp-browserify');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
function cleanAll(cb) {
return gulp.src([
"./tmp/",
"./dist/js"
], { read: false, allowEmpty: true })
.pipe(clean());
}
function transpileTS() {
const tsproject = ts.createProject('./tsconfig.json');
return tsproject
.src()
.pipe(sourcemaps.init())
.pipe(tsproject()).js
.pipe(sourcemaps.write('./sourcemaps'))
.pipe(gulp.dest('./tmp/js'));
}
function minJS() {
return gulp
.src('./tmp/js/Index.js')
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(browserify())
// .pipe(uglify())
.pipe(concat('index.min.js'))
.pipe(sourcemaps.write('./sourcemaps'))
.pipe(gulp.dest('./dist/js'))
}
exports.default = series( cleanAll, transpileTS, minJS );
I'm importing and using my library like this - Scripts/Index.ts
:
import * as $ from "jquery";
import Lib from "library";
$(()=>{
console.log("creating lib instance.");
new Lib({message:"example message here"});
});
But when I launch this in a browser - dist/index.html
:
<script src="js/Index.min.js"></script>
I get an error:
Uncaught TypeError: library_1.default is not a constructor
Indeed, library_1.default
doesn't exist, library_1
does though:
> library_1
< class Lib {
constructor(options) {
console.log("It works!");
console.log(options.message);
}
}
How do I fix this? I suspect the error is somewhere in the library, but I have no idea where.
I've figured it out.
In my lib.ts
I had to change the way I export my class:
import Options from "./options";
class Lib{
constructor(options:Options){
console.log("It works!");
console.log(options.message);
}
}
export default Lib;
Next, I changed rollup.config.js
(added exports:'default'
) to keep the exported class global:
...
{
file: 'dist/lib.umd.js',
format: 'umd',
name: 'Lib',
exports:'default'
},
...
I also had to change the library's package.json
- I pointed main
to my es module as it looks like browserify just ignores the module directive.
I also ended up removing the exports
section as some of our other projects (not using browserify) kept using the require
file, not the import
one:
{
"name": "library",
"version": "1.0.16",
"description": "example library",
"main": "dist/lib.esm.js",
"module":"dist/lib.esm.js",
"types":"dist/types/lib.d.ts",
"license": "MIT",
"private": true,
"devDependencies": {
"@rollup/plugin-typescript": "^8.3.0",
"rollup": "^2.67.0",
"tslib": "^2.3.1",
"typescript": "^4.5.5"
},
"exports": {
"import": "./dist/lib.esm.js",
"require": "./dist/lib.umd.js"
},
"scripts": {
"build": "rollup -c rollup.config.js"
}
}
Finally, I had to use babelify in my consumer project to avoid ParseError: 'import' and 'export' may appear only with 'sourceType: module'
while running browserify.
The full source is available here