I have a project that builds a typescript library with various assets. Here's how its webpack is configured:
const path = require("path");
module.exports = {
entry: "./src/index.ts",
mode: "development",
module: {
rules: [
{
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: [{ loader: "@svgr/webpack", options: { typescript: true } }],
},
{
test: /\.s[ac]ss$/i,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
output: {
filename: "my-icons.js",
path: path.resolve(__dirname, "dist"),
library: {
name: "my-icons",
type: "umd",
},
},
};
That works fine. It transforms the assets, complies the Typescript, and bundles it all. But it doesn't generate .d.ts
files, which are needed by any Typescript consumers of the library.
Here's what my research has shown:
The
ts-loader
package recommends using a DeclarationBunderPlugin. But this is an experimental project that hasn't been updated in six years.Some other plugins to handle this that don't seem particularly well supported. See dts-bundle referenced in this SO question as well as other plugin code provided in answers to that question. There is also a plugin referenced in this SO question.
I've also seen recommendations to just run
tsc
and copy over the.d.ts
files. See the comments in this SO question, for example. See also this even older SO question. That's fine, but I was a little surprised not to see any tooling to handle this.As far as I can tell, the webpack documentation is silent on this in its typescript section.
Is there a recommended/best/canonical approach for this? Is it just some version of 3. above--i.e., generate your .d.ts
files separately and manually add them to your distribution package?
I've put together a small example repo that demonstrates the problems with just using tsc
or webpack
on their own.
CodePudding user response:
OK, I feel sort of dumb, but, on the other hand, this does not seem to be super well-documented.
It turns out, if your webpack and tsconfig are both set up to compile/build into the same directory, and your tsconfig is set to emit declarations, AND your webpack library is set to target the same entrypoint as the main entry in your package.json (e.g., index.js), it will work correctly.
So--
package.json:
//excerpt
"main": "lib/index.js",
"types": "lib/index.d.ts",
"scripts": {
"build": "rimraf ./lib && webpack"
},
tsconfig.json
//excerpt
"compilerOptions": {
"outDir": "lib",
"declaration": true
}
webpack.config.js
const path = require("path");
module.exports = {
entry: "./src/index.ts",
mode: "development",
module: {
rules: [
{
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: [{ loader: "@svgr/webpack", options: { typescript: true } }],
},
{
test: /\.s[ac]ss$/i,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
output: {
filename: "index.js",
path: path.resolve(__dirname, "lib"),
library: {
name: "my-icons",
type: "umd",
},
},
};
A working example is in this repo. Just do npm install && npm run build