Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple output targets with typescript declarations enabled #247

Closed
maniax89 opened this issue Mar 9, 2020 · 24 comments · Fixed by #687
Closed

Support multiple output targets with typescript declarations enabled #247

maniax89 opened this issue Mar 9, 2020 · 24 comments · Fixed by #687

Comments

@maniax89
Copy link

maniax89 commented Mar 9, 2020

  • Rollup Plugin Name: @rollup/typescript
  • Rollup Plugin Version: 4.0.0

Feature Use Case

I am coming from rollup-plugin-typescript2 which seemed to allow setting declaration: true as well as supporting multiple output targets in the rollup.config.js like:

// rollup.config.js
export default {
  output: [
    {
      file: 'index.js',
      format: "cjs"
    },
    {
      file: 'index.es.js',
      format: 'es'
    }
  ],
  plugins: [typescript()]
}

partial tsconfig.json:

{
  "compilerOptions": {
    "rootDir": "src",
    "declarationDir": "dist",
    "declaration": true,
    "isolatedModules": false
  }
}

This plugin seems to only allow setting a single output target with the dir attribute, otherwise we get the "dir must be set when specifying declaration" error.

Feature Proposal

Allow setting multiple output targets and default the declarations to the same directory as the current working directory of the output targets. From rollup-plugin-typescript2:

This plugin respects declaration: true in your tsconfig.json file. When set, it will emit *.d.ts files for your bundle. The resulting file(s) can then be used with the types property in your package.json file as described here. By default, the declaration files will be located in the same directory as the generated Rollup bundle. If you want to override this behavior and instead use the declarationDir set useTsconfigDeclarationDir to true in the plugin options.

I'm not sure its well defined for multiple output files, but maybe the default can just be the declarationDir specified instead of requiring rollup's output to specify a dir

@NotWoods
Copy link
Member

NotWoods commented Mar 9, 2020

Does it work if you set two different dir options, or turn off declarations for the second output? rollup-plugin-typescript2 achieves this by writing files directly instead of emitting Rollup assets, and I'd like to work around that if possible :)

@maniax89
Copy link
Author

maniax89 commented Mar 9, 2020

I can try the two dir options tomorrow. For turning off declarations for the second output, would I have to use a different configuration template to achieve that than what I have posted? Wasn't sure how to specify output-specific plugin options

@NotWoods
Copy link
Member

NotWoods commented Mar 9, 2020

Oops, I wasn't thinking straight...you'd need to provide two configurations. That's not ideal but should work as a quick fix for now until we improve the plugin further.

@Tylerian
Copy link

Tylerian commented Mar 18, 2020

I'm also facing this same issue, and when using a single output object with a dir property, TS definition files are not being generated.

What do you mean by using two configurations @NotWoods?
Can you show us a quick example?

@NotWoods
Copy link
Member

@Tylerian something like:

// rollup.config.js
export default [
  {
    output: [
      {
        dir: 'dist',
        format: 'es'
      }
    ],
    plugins: [typescript({ declaration: true }))]
  },
  {
    output: [
      {
        file: 'index.cjs',
        format: 'cjs'
      }
    ],
    plugins: [typescript({ declaration: false })]
  }
];

I'm working on updating the plugin so dir: undefined + declaration: true just results in the declaration files being ignored.

@k2snowman69
Copy link

k2snowman69 commented Apr 8, 2020

@NotWoods FYI this did not work for me personally. I am curious, what's the harm in generating the declaration types twice other than wasted CPU? Wouldn't the second build output just overwrite the firsts?

@openscript
Copy link

openscript commented Apr 10, 2020

For me this worked, even though it's a bit ugly:

import typescript from '@rollup/plugin-typescript';
import pkg from './package.json';

const globals = { react: 'React' };
const defaults = {
	input: 'src/index.tsx',
	external: [
		...Object.keys(pkg.peerDependencies || {})
	],
	plugins: [
		typescript()
	]
}

export default [
	{
		...defaults,
		output: [
			{ file: pkg.main, format: 'cjs', globals },
			{ file: pkg.browser, name: 'ReactLib', format: 'iife', globals }
		]
	}, {
		...defaults,
		plugins: [
			typescript({ declaration: true, declarationDir: 'dist' })
		],
		output: [
			{ dir: 'dist', format: 'es', globals }
		]
	}
];

@marlon-tucker
Copy link

I'm running up against something similar to this, if you would prefer me to submit a new issue I wll.

We use rollup to generate a single umd build for typescript, and we have a entry file called public_api.ts. We were using the previous typescript rollup plugin and that enabled us to output declaration files into a different target directory while still producing a single umd output file. We used rollup's output.file option to control what the output filename is of the generated umd file. We don't care the typescript declaration files are using the es module format as because everything is flowing from a single entry point, as far as library consumers are concerned the declarations match up.

The new rollup typescript plugin enforces the use if rollup's output.dir option if it finds a setting for declarationDir in the tsconfig - this appears to go against the intent of rollup generating a single umd file, and it also means we can no longer nicely control the output file name, it gets written as public_api.js.

Enforcing the use of chunks to deal with typescript declarations sounds like the wrong way to go imo.

@shellscape
Copy link
Collaborator

Hey folks. This is a call for contribution and help in resolving this TypeScript plugin issue. We're working with limited resources and the folks who can help have limited time. If you can help by triaging and submitting a Pull Request, we'd be happy to review it.

@wrumsby
Copy link

wrumsby commented Jul 23, 2020

Based on @openscript's solution I was able to get my configuration working and then make sense of the problems I was having.

Firstly you need to make sure that your tsconfig.json (or the tsconfig passed to the plugin):

  • declares "declaration": false - i.e. you want the default behaviour to not create declaration files
  • does not declare an outDir - i.e. you want the format-specific output in rollup.config.js (or equivalent) to declare the dir or file for output

The default export for my rollup.config.js looks like this:

const rollup = (_args) => {
  const input = 'src/index.ts';
  const external = [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})];

  return [
    // cjs configuration
    {
      input,
      output: getOutput('cjs'),
      plugins: getPlugins('cjs'),
      external,
    },
    // esm configuration
    {
      input,
      output: getOutput('esm'),
      plugins: getPlugins('esm'),
      external,
    },
  ];
};

export default rollup;

getOutput looks like this:

const getOutput = (format = 'esm') => {
  if (format === 'esm') {
    return { dir: path.dirname(pkg.module), format };
  }

  // pkg is package.json
  return { file: pkg.main, format };
};

and getPlugins looks like this:

const getPlugins = (format = 'esm') => {
  const typeScriptOptions = format === 'esm' ? { declaration: true, declarationDir: path.dirname(pkg.module) } : {};

  return [
    // @rollup/plugin-node-resolve
    resolve({
      browser: true,
      extensions,
    }),
    typescript(typeScriptOptions),
    // I'm using @rollup/plugin-babel so that I can use @babel/preset-env and @babel/preset-react
    babel({
      // this is needed because we're using TypeScript
      babelHelpers: 'bundled',
      extensions,
    }),
  ];
};

It took me a while to figure out what was going on here, but:

  • for the CommonJS build you only want Rollup to generate a single file (i.e. rollup to a single file) so declaring file for this format is fine
  • we want to generate TypeScript declaration files so that TypeScript consumers can use our typings
  • since we've decided to generate the declarations when producing the ESM distribution we want to use the dir option because the Rollup file for ESM and typings should go in the same directory - that's why dir for output and declarationDir for the TypeScript plugin are for the same directory

Essentially it seems that if you try to generate declarations then you need to use dir for output.

My approach means that using this Rollup configuration is the only way I compile my TypeScript code (i.e. I don't use tsc), so my build step in pacakage.json is:

"build": "rollup -c"

Hope that helps!

(As a suggestion maybe an edited form of this comment could go in the README for the plugin if people think that helps.)

@stale stale bot added the x⁷ ⋅ stale label Sep 27, 2020
@stale
Copy link

stale bot commented Sep 28, 2020

Hey folks. This issue hasn't received any traction for 60 days, so we're going to close this for housekeeping. If this is still an ongoing issue, please do consider contributing a Pull Request to resolve it. Further discussion is always welcome even with the issue closed. If anything actionable is posted in the comments, we'll consider reopening it.

@ghost
Copy link

ghost commented Sep 30, 2020

Issue still relevant!!!

works withiout declaration: true and ourDir, while add props those in config then

 (plugin typescript) Error: @rollup/plugin-typescript: 'outDir' or 'declarationDir' must be specified to generate dec
laration files.
Error: @rollup/plugin-typescript: 'outDir' or 'declarationDir' must be specified to generate declaration files.

with multiple outputs.

change file to dir - works but named files doesn't generate. Reopen issue please.

@shellscape
Copy link
Collaborator

We welcome contribution

@marlon-tucker
Copy link

I've stopped using the rollup typescript plugin in favour of using tsc to transpile the Typescript into an intermediate build folder, then I use rollup to bundle that transpiled code and output it to the desired destination.

Bit more to setup initially but it gives me far greater control over the process.

@benmccann
Copy link
Contributor

Can we reopen to track this?

@shellscape
Copy link
Collaborator

@benmccann not until someone is willing to take this on. It was closed as stale bc it got no traction.

@benmccann
Copy link
Contributor

@shellscape ok. I'm currently investigating this, so can we reopen as a result?

@shellscape
Copy link
Collaborator

Yessir!

@Enteleform
Copy link

@benmccann Thanks for submitting a PR for this! Can you please provide a usage example?

@skjnldsv
Copy link

@benmccann Thanks for submitting a PR for this! Can you please provide a usage example?

@benmccann any news?

@distinctdan
Copy link

Unfortunately this still appears to be broken, the only way I can get declarations to work for multiple outputs is to do separate top-level tasks.

@yangliguo7
Copy link

yangliguo7 commented Nov 15, 2022

I found that the single-file build also has such a problem.

"rollup": "^3.2.5",
"@rollup/plugin-typescript": "^9.0.2",

export default defineConfig({
  input: 'src/index.ts',
  output: [
    {
      dir: 'dist/es',
      format: 'es',
      manualChunks: {
        lodash: ['lodash-es']
      }
    },
  ],
  plugins: [
    typescript({
      tsconfig: 'tsconfig.json',
    })
  ],
})
tsconfig.json

{
    compilerOptions:{
       "declaration": true,
       "declarationDir": "dist/types"
    }
}

[!] (plugin typescript) RollupError: @rollup/plugin-typescript: Path of Typescript compiler option 'declarationDir' must be located inside Rollup 'dir' option.

@gunslingor
Copy link

Man... I've spent the last 3 days trying to use rollup to build a tiny well behaved hello world react component library. Tutorials, rollup.config.js, package.json, & tsconfig formats and integrations seem to be ever changing in an unstable way, they all seem to depend on each other but differ vastly. Is there a better way to use Rollup? After all these changes to my project from trying to use rollup, I'm questioning how this will mess up my developer run mode. Might have to revert all rollup stuff, is there a better tool or standard tutorial for a well behaved NPM package these days? Thanks, frustrated.

@shellscape
Copy link
Collaborator

yeah, while I'm sorry you're having trouble with third party resources and rollup, this isn't the place to vent. we have discussions, a discord, and there's always Twitter and reddit. we've all been there, but please choose an appropriate medium next time.

@rollup rollup locked as resolved and limited conversation to collaborators Feb 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.