I want to create a library using TypeScript. It should be available for Node and Browser environments.
I started with the package.json file and installed esbuild
as a dependency and typescript
as a dev dependency. The result is
{
"name": "my-lib",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc && esbuild ./dist/lib/index.js --bundle --minify --sourcemap --outfile=./bundle/index.js"
},
"dependencies": {
"esbuild": "0.14.36"
},
"devDependencies": {
"typescript": "4.6.3"
}
}
The tsconfig.json file contains
{
"pilerOptions": {
"baseUrl": ".",
"declaration": true,
"esModuleInterop": true,
"lib": [ "dom", "esnext" ],
"module": "monjs",
"outDir": "dist",
"resolveJsonModule": true,
"strict": true,
"target": "es2019",
},
"include": [
"./**/*.ts"
],
"exclude": [
"./dist"
]
}
Inside the root directory I have a lib directory holding an index.ts file which exports all the "public" functions, e.g.
const sum = function (a: number, b: number): number { return a + b; };
export { sum };
Besides that I have a test directory right next to the lib directory, holding some .ts files. I want to test the build
script and added the following index.html to the root directory
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='./bundle/index.js'></script>
</head>
<body>
<div>
Loading bundle...
</div>
</body>
</html>
<script type="text/javascript">
window.onload = () => {
console.log('ready');
const result = sum(1, 2);
console.log({ result });
const anotherResult = window.sum(1, 2);
console.log({ anotherResult });
};
</script>
Unfortunately I get an Uncaught ReferenceError
because it is not able to find the function sum
. The folder structure before running npm install && npm run build
is
Does someone know what's wrong or missing here?
I want to create a library using TypeScript. It should be available for Node and Browser environments.
I started with the package.json file and installed esbuild
as a dependency and typescript
as a dev dependency. The result is
{
"name": "my-lib",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc && esbuild ./dist/lib/index.js --bundle --minify --sourcemap --outfile=./bundle/index.js"
},
"dependencies": {
"esbuild": "0.14.36"
},
"devDependencies": {
"typescript": "4.6.3"
}
}
The tsconfig.json file contains
{
"pilerOptions": {
"baseUrl": ".",
"declaration": true,
"esModuleInterop": true,
"lib": [ "dom", "esnext" ],
"module": "monjs",
"outDir": "dist",
"resolveJsonModule": true,
"strict": true,
"target": "es2019",
},
"include": [
"./**/*.ts"
],
"exclude": [
"./dist"
]
}
Inside the root directory I have a lib directory holding an index.ts file which exports all the "public" functions, e.g.
const sum = function (a: number, b: number): number { return a + b; };
export { sum };
Besides that I have a test directory right next to the lib directory, holding some .ts files. I want to test the build
script and added the following index.html to the root directory
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='./bundle/index.js'></script>
</head>
<body>
<div>
Loading bundle...
</div>
</body>
</html>
<script type="text/javascript">
window.onload = () => {
console.log('ready');
const result = sum(1, 2);
console.log({ result });
const anotherResult = window.sum(1, 2);
console.log({ anotherResult });
};
</script>
Unfortunately I get an Uncaught ReferenceError
because it is not able to find the function sum
. The folder structure before running npm install && npm run build
is
Does someone know what's wrong or missing here?
Share Improve this question asked Apr 14, 2022 at 9:12 user17298649user17298649 5-
Why
"module": "monjs"
if you want to use the library in a browser? – Bergi Commented Apr 18, 2022 at 23:40 -
@Bergi this package should run inside Node and Browser environments. Should I use
"module": "umd"
instead? – user17298649 Commented Apr 19, 2022 at 11:36 - Yes, if you want to build a file that can be distributed to either, UMD will be necessary. Or you distribute two separate files in the package, one for node and one for browsers. – Bergi Commented Apr 19, 2022 at 12:52
-
Also it's not really clear what you're trying to achieve here. Why is
esbuild
not a dev dependency? Why do you want to bundle your library at all, shouldn't that be done by the application that uses the library? – Bergi Commented Apr 19, 2022 at 12:53 - how are you bundling function using esbuild? – Yilmaz Commented Apr 21, 2022 at 22:30
3 Answers
Reset to default 3If you want include your bundled javascript into html file via script tag (as in your example), you should add sum
variable to page global variables scope like that:
const sum = function (a: number, b: number): number { return a + b; };
window.sum = sum;
// or `globalThis.sum = sum;`
Defining variable in global page scope makes it sure that no minification or renaming processes in bundler will break your app.
It would be better for you to check the concept of Commonjs and ECMAScript Module(ESM) before working. The pilerOptions.module
in tsconfig.json
is Commonjs, which is the bundling method used by Node.js. This does not work with browser. This is because the browser does not have the require
method which can recognize the exports
object and the module
object, which is available globally in Node.js.
Therefore, when creating modules that support browsers, usually bundle them in UMD format using Webpack. If you don't support older browsers, you can think of bundling in the ESM way, even without a Webpack.
First, modify tsconfig.json
as follows:
{
"pilerOptions": {
"baseUrl": ".",
"declaration": true,
"esModuleInterop": true,
"lib": [ "dom", "esnext" ],
"module": "esnext", // update
"outDir": "dist",
// "resolveJsonModule": true,
"strict": true,
"target": "es2019",
},
"include": [
"./**/*.ts"
],
"exclude": [
"./dist"
]
}
Next, modify the following HTML as follows:
<!DOCTYPE html>
<html>
<head>
<script type="module">
import {sum} from './dist/index.js';
window.onload = () => {
console.log('ready');
const result = sum(1, 2);
console.log({ result });
const anotherResult = sum(1, 2);
console.log({ anotherResult });
};
</script>
</head>
<body>
<div>
Loading bundle...
</div>
</body>
</html>
You can create library that work in your browser after npm install && npm run build
.
If your library can be imported from another bundler (like a webpack), you want it to work in a browser, and you want to implement it using tsc only, see the following link.
Your code is fine, the problem is that you are using bad export. Exports a function that is never used and that is why the error. Then I show you how to solve this.
You must first bear in mind that nothing is exported in the index.ts. Rather the index.ts receives functions from other JS modules. Then create a Sum.TS file that will be a module where you will write the following code:
sum.ts
const sum = function (a: number, b: number): number { return a + b; };
export { sum };
In Index.ts imports the sum function of the module sum.ts the file must remain like this:
index.ts
import { sum } from "./sum";
sum
In this way you already have the sum function available to use in the index.html.
When you export functions these are not available in the piled code. Only imports are available in the piled code.
If you want to use the index.ts to store public functions the code should be like this:
const sum = function (a: number, b: number): number { return a + b; };
sum
update
Just change your index.ts to this:
const sum = function (a: number, b: number): number { return a + b; };
sum
and your index.html to this:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='./bundle/index.js'></script>
</head>
<body>
<div>
Loading bundle...
</div>
</body>
</html>
<script type="text/javascript">
window.onload = () => {
console.log('ready');
const result = sum(1, 2);
console.log({ result });
const anotherResult = sum(1, 2);
console.log({ anotherResult });
};
</script>
Don't export functions in index.ts as you won't be able to do them in the browser.