Parcel API Does Not Generate Types
🐛 bug report
I am unable to get a valid index.d.ts to generate. I am using the Parcel API. It is mostly undocumented in the API how one would go about this. I found this issue which gave me the idea to make a 'types' target, which does generate an index.ts file, but it has multiple export defaults, making it invalid.
🎛 Configuration (.babelrc, package.json, cli command)
Keep in mind that this is using the API. I get an error if I don't include a distDir, I've also tried having a top level types outside of targets with a dist/index.d.ts, but that wont work either.
{
entry: `${SOME_VALID_ENTRY}`,
targets: {
'esm-node': {
context: 'node',
engines: {
node: `>=${MODERN_NODE_VERSION}.0.0`,
},
outputFormat: 'esmodule',
isLibrary: true,
distDir: './dist/esm-node',
},
esm: {
context: 'browser',
engines: {
browsers: BROWSERS_RULE,
},
outputFormat: 'esmodule',
distDir: './dist/esm',
},
cjs: {
context: 'node',
engines: {
node: `>=${LEGACY_NODE_VERSION}.0.0`,
},
outputFormat: 'commonjs',
distDir: './dist/cjs',
},
types: {
distDir: './dist',
},
},
}
🤔 Expected Behavior
I'd expect that given a TS file, a .d.ts file is generated. In the above config, that it is placed inside the ./dist directory.
😯 Current Behavior
Without specifying a types target, no types are produced, when included, it generates an invalid typescript file.
💁 Possible Solution
I'd like to have clear documentation and a setting for where to put the types. Perhaps it could even look like:
{
typeDeclarationDest: './some/path/types.d.ts',
targets: { /* blah blah */ }
}
🔦 Context
It is game breaking for my attempt at using parcel as part of a library in which it is expected to produce the declaration files (or atleast, move the ones typescript produces to the correct location).
💻 Code Sample
import { Parcel } from '@parcel/core';
const bundler = new Parcel({
entry: `${SOME_VALID_ENTRY}.ts`,
targets: {
'esm-node': {
context: 'node',
engines: {
node: `>=${MODERN_NODE_VERSION}.0.0`,
},
outputFormat: 'esmodule',
isLibrary: true,
distDir: './dist/esm-node',
},
esm: {
context: 'browser',
engines: {
browsers: BROWSERS_RULE,
},
outputFormat: 'esmodule',
distDir: './dist/esm',
},
cjs: {
context: 'node',
engines: {
node: `>=${LEGACY_NODE_VERSION}.0.0`,
},
outputFormat: 'commonjs',
distDir: './dist/cjs',
},
},
});
await bundler.run();
Do this with any valid typescript and a tsconfig.json and you will not receive a declaration file.
🌍 Your Environment
| Software | Version(s) |
|---|---|
| Parcel | 2.8.3 |
| Node | 18.11.0 |
| npm/Yarn | npm 9.4.0 |
| Operating System | Mac OS Ventura 13.2.1 |
Love Parcel! ❤️
Maybe related parcel build --target types when types is declared in targets doesn't produce a type declaration either
I really wanted to have multiple target exports with types, and I had to do a very smelly solution. The idea is to simply replace the targets in package.json using replace-in-file package (which I had already included as dev dep for some other stuff).
For example, I have 3 targets at lib, lib/common and lib/contracts. I have a single source and 2 targets + type target as:
"source": "src/index.ts",
"types": "lib/index.d.ts",
"cjs": "lib/index.cjs",
"mjs": "lib/index.mjs",
My targets field is as follows:
"targets": {
"cjs": {
"outputFormat": "commonjs",
"isLibrary": true,
"context": "node"
},
"mjs": {
"outputFormat": "esmodule",
"isLibrary": true,
"context": "node"
}
},
I wrote a small script that uses replace-in-file package to replace these lines from the current target to my desired target, and I specify that mapping with a step number.
const replace = require('replace-in-file');
const srcDir = 'src';
const outDir = 'lib';
async function main(from, to) {
const entriesFrom = [
`"source": "${srcDir}/${from}index.ts",`,
`"types": "${outDir}/${from}index.d.ts",`,
`"cjs": "${outDir}/${from}index.cjs",`,
`"mjs": "${outDir}/${from}index.mjs",`,
];
const entriesTo = [
`"source": "${srcDir}/${to}index.ts",`,
`"types": "${outDir}/${to}index.d.ts",`,
`"cjs": "${outDir}/${to}index.cjs",`,
`"mjs": "${outDir}/${to}index.mjs",`,
];
const mappings = entriesFrom.map((v, i) => ({
from: v,
to: entriesTo[i],
}));
mappings.map(({from, to}) =>
replace.sync({
files: './package.json',
from,
to,
})
);
}
if (require.main === module) {
if (process.argv.length !== 3) {
throw new Error('Usage: node replace.cjs stepNo');
}
const steps = ['', 'common/', 'contracts/', ''];
const stepNo = parseInt(process.argv[2]);
if (stepNo === 0 || stepNo >= steps.length) {
throw new Error('Make sure: 0 < step no < step count');
}
main(steps[stepNo - 1], steps[stepNo]);
}
My custom scripts in package.json is then:
"prebuild": "yarn clean",
"build": "parcel build && yarn step 1 && parcel build && yarn step 2 && parcel build && yarn step 3",
"postbuild": "yarn check",
"step": "node buildstep.cjs",
"clean": "rimraf ./lib",
I HATE this solution and I hope things get fixed.
This is an issue for me as well. Can't get types generated when using targets.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs.