Security News
RubyGems.org Adds New Maintainer Role
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
@wessberg/rollup-plugin-ts
Advanced tools
A Typescript Rollup plugin that bundles declarations and respects Browserslists
A Typescript Rollup plugin that bundles declarations and respects Browserslists
This is a Rollup plugin that enables integration between Typescript, Babel, Browserslists, and Rollup. It is first and foremost a Typescript plugin that enables full interoperability with Rollup. With it comes very powerful bundling and tree-shaking of generated Typescript declaration files that works seamlessly with code splitting.
In comparison with the official plugin, this one has several significant improvements:
.d.ts
) are supported and fully supports code splitting$ npm install @wessberg/rollup-plugin-ts
$ yarn add @wessberg/rollup-plugin-ts
$ pnpm add @wessberg/rollup-plugin-ts
Using the plugin is as simple as it can be. Here's an example within a Rollup config:
import ts from "@wessberg/rollup-plugin-ts";
export default {
// ...
plugins: [
ts({
/* Plugin options */
})
]
};
Without any options, the plugin will "just work":
tsconfig.json
file closest to the current working directory will be resolved, if any. Otherwise, the default Typescript options will be used..browserslistrc
file or browserslist
property within the package.json
file closest to the current working directory will be resolved and used to decide the Typescript ECMAScript version target, if any. Otherwise, the declared target
within the resolved tsconfig.json
file will be used, if any such file exists, and if not, the default Typescript target will be used.This plugin works very well with just Typescript.
The tsconfig.json
file closest to your project will be resolved and used in combination with Rollup.
If your config has a different name, or if you use different configs dynamically depending on the environment, you can provide the location for the tsconfig
in the plugin options:
ts({
tsconfig: PRODUCTION ? "tsconfig.prod.json" : "tsconfig.json"
});
You an also pass in CompilerOptions directly, rather than provide the path to a tsconfig
:
ts({
tsconfig: {
target: ScriptTarget.ES2018,
allowSyntheticDefaultImports: true,
allowJs: true
}
});
You can also pass in a function that receives whatever CompilerOptions
that could be resolved relative to the current working directory, but then allow you to override the options:
ts({
tsconfig: resolvedConfig => ({...resolvedConfig, allowJs: false})
});
The above example is based on the assumption that a file can be resolved with the name tsconfig.json
, and if not, the Typescript's default CompilerOptions
will be used.
But if you want to provide the name of the tsconfig
to override, you can also pass in an object following the following form:
ts({
tsconfig: {
fileName: "my-awesome-tsconfig.json",
hook: resolvedConfig => ({...resolvedConfig, allowJs: false})
}
});
If there is a .browserslistrc
file or the nearest package.json
contains a Browserslist configuration, a target ECMAScript version will be decided based on that one, rather than respecting the target
property of the matched tsconfig
.
If you do not want this behavior, you can disable it as described here.
This plugin makes sure that the helper functions that may be emitted within the output generated by Typescript will not be duplicated across files and chunks. Instead, they will automatically be divided into chunks and imported across Rollup chunks. You don't have to do anything!
If there is a .browserslistrc
file or the nearest package.json
contains a Browserslist configuration, this is the default behavior! Rather than use the target
property of the nearest tsconfig
, it will be decided based on the Browserslist.
You can explicitly pass in Browserslist options. Here's an example with a raw Browserslist query:
ts({
browserslist: ["last 1 version", "> 1%"]
});
You can also provide a configuration object instead of a raw query. Here's one with a baked-in query:
ts({
browserslist: {
query: ["last 1 version", "> 1%"]
}
});
...And here's one with a path
property pointing to a file that contains a Browserslist:
ts({
browserslist: {
path: ".mybrowserslistrc"
}
});
If no Browserslist can be found, or if you simply don't want to use one, that's completely OK!
In such cases, the target
property of the nearest tsconfig
will be used (or use the Typescript default setting if no such file exists).
You can explicitly request that no Browserslist will be used by setting the browserslist
property to false
in the plugin options:
ts({
browserslist: false
});
This plugin makes it really easy to use Typescript for reporting diagnostics, generating declaration files, and stripping types, but then using Babel for all other syntax transformations.
One very strong use case for this is to use @babel/preset-env
. Another one is that you get the entire ecosystem of Babel plugins at your disposal.
To use Babel, simply set the transpiler
plugin option to "babel"
:
ts({
transpiler: "babel"
});
That's it! The plugin will attempt to locate a babel.config.js
file or a .babelrc
file and use the options, plugins, and presets found there.
By default, some combination of presets and plugins will be applied depending on the config options you provide. See this section for more details.
This plugin will apply syntax transformations from Babel presets and plugins on a file-by-file basis. However, if a a minification-related plugin or preset such as babel-preset-minify is found within the Babel options, these transformations will be applied per chunk. This enables the minification presets and plugins to perform better as it can now mangle in relation to the entire chunk and better remove unwanted characters such as whitespace. All of this works automatically.
@babel/runtime
and external helpersThis plugin will automatically make sure to avoid duplication of emitted Babel helpers. Rollup will automatically split these into chunks and re-use them across the chunks that Rollup generates. You don't have to do anything.
@babel/runtime
and polyfillsBabel supports injecting polyfills where needed and in relation to the target environment. By default, this plugin will not add polyfills to your chunks since there are arguably better ways of applying polyfills such as lazy-loading depending on feature support or using something like Polyfill.app.
If you would like this behavior, simply add either @babel/plugin-transform-runtime
to your Babel config with the corejs
option set to true, or add @babel/preset-env
to your Babel config with the useBuiltIns
option set to usage
.
CustomTransformers
This plugin enables you to pass in CustomTransformers
which allows you to transform the Typescript AST during code transpilation.
This enables you to very efficiently transform Typescript before code generation and additionally enables you to use this plugin with tools that leverage this, such as some modern web frameworks and libraries do.
Typescript declaration files are normally distributed in a folder structure that resembles the structure of the source folder.
With tsc
, you would get something like this:
Rollup is a bundler, and with it, we can produce clean, small files that are easy to distribute.
With rollup-plugin-ts
, declaration files will be bundled, tree-shaken and emitted alongside the chunks emitted by Rollup:
And, it even works in complex code splitting scenarios:
ts({
// If your tsconfig is already called 'tsconfig.json', this option can be left out
tsconfig: "tsconfig.json",
// If there is no .browserslistrc within your project, and if your package.json doesn't include a Browserslist property, this option can be left out
browserslist: false
});
As described here, by default, the plugin will attempt to locate a Browserslist automatically. This example shows how you can provide one explicitly
ts({
browserslist: ["last 1 version", "> 1%"]
});
// or
ts({
browserslist: {path: ".mybrowserslistrc"}
});
As described here, a babel.config.js
or .babelrc
file will automatically be found by the plugin if available. This example shows how you can provide one explicitly.
And, as described here, the same goes for Browserslists.
ts({
transpiler: "babel",
browserslist: ["last 1 version", "> 1%"],
babelConfig: {
plugins: ["my-babel-plugin"]
}
});
ts({
transformers: {
before: [myTransformer1, myTransformer2],
after: [myTransformer3, myTransformer4],
afterDeclarations: [myTransformer5, myTransformer6]
}
});
This example shows how you can use this plugin to accomplish quite advanced things:
const IS_PRODUCTION = process.env.NODE_ENV === "production";
const BUNDLE_TARGET = process.env.BUNDLE_TARGET;
const APP_ROOT = "/some/project/root/folder";
const awesomeFrameworkTransformers = getAwesomeFrameworkCustomTransformers();
ts({
// Use Babel for Syntax transformations
transpiler: "babel",
// Don't use process.cwd(), but instead another root directory
cwd: APP_ROOT,
// Load a different tsconfig file in production
tsconfig: IS_PRODUCTION ? "tsconfig.prod.json" : "tsconfig.json",
// Load a different browserslist if currently targeting a modern environment
browserslist: {
path: BUNDLE_TARGET === "modern" ? ".browserlistrc-modern" : ".browserslistrc-legacy"
},
// Load a different babel config file in production
babelConfig: IS_PRODUCTION ? "babel.config.prod.js" : "babel.config.js",
// Exclude files within node_modules when not in production
exclude: IS_PRODUCTION ? [] : ["node_modules/**/*.*"],
// Apply CustomTransformers, for example to transform the Source Code with a framework that uses some
transformers: awesomeFrameworkTransformers
});
You can use pass a specific TypeScript to use as an option. This may be useful if you are using different TypeScript versions across packages inside a monorepo and you want to use a specific one with rollup-plugin-ts
:
ts({
typescript: specialTypescriptVersion
});
rollup-plugin-ts
provides a few hooks that allow you to hook into and augment the internal behavior of the plugin.
These can be provided in the plugin options for the hook
property:
ts({
hook: {
// Add hooks here
}
});
The next few subsections describe the different hooks that can be provided
outputPath
hookType: (path: string, kind: "declaration" | "declarationMap" | "buildInfo") => string | undefined
The outputPath
hook can be used to rewrite the location on the filesystem that assets produced by rollup-plugin-ts
are written to.
It is invoked immediately before assets such as declarations or declaration maps are emitted.
The hook is invoked with the output path as well as the kind of asset the path represents as arguments.
If you return a string
from the hook, the alternative location will be used instead. If you return undefined, the current path will be used.
ts({
hook: {
outputPath: (path, kind) => rewritePathSomehow(path, kind)
}
});
For example, the path
may be /some/path/index.d.ts
, and kind
be declaration
, and you might want to rewrite this to /some/path/my-typings.d.ts
.
diagnostics
hookType: (diagnostics: readonly Diagnostic[]) => readonly Diagnostic[]|undefined
The diagnostics
hook can be used to read, alter, and extend the diagnostics generated by TypeScript immediately before they are emitted as errors via Rollup.
Normally, Rollup will crash on the first discovered error, but there may be several diagnostics, all of which may be of interest to you. This hook gives you access to all of them.
You can also use this hook if you want to silence specific kinds of Diagnostics or even add your own.
The plugin options are documented in more detail across this README, but the full list of options is:
transpiler
Type: "typescript" | "babel"
Can be any of "babel"
or "typescript"
(default: "typescript"
).
See this section and this section for details on how rollup-plugin-ts
works when "babel"
is being used as a transpiler.
babelConfig
Type: string | Partial<IBabelInputOptions>
This option will only be respected when "babel"
is being used as the transpiler
and can be used to provide a Babel config or a path to one.
tsconfig
Type: string | Partial<CompilerOptions> | Partial<Record<keyof CompilerOptions, string | number | boolean>> | ParsedCommandLine | TsConfigResolver | TsConfigResolverWithFileName
Provide the Typescript CompilerOptions to use, or a path to a tsconfig
with this property.
See this section for details on the many ways this property can be configured.
browserslist
Type: false | string[] | string | BrowserslistConfig
Provide the Browserslist to use, or a path to a .browserslistrc
with this property.
See this section for details on the many ways this property can be configured.
cwd
Type: string
Use this property to overwrite whatever is considered the root directory. The default value is process.cwd()
.
typescript
Type: typeof import("typescript")
Use this property to pass a specific version of TypeScript to use.
transformers
Type: (CustomTransformers | CustomTransformersFunction)[] | CustomTransformers | CustomTransformersFunction
Use this property to provide Typescript CustomTransformers
.
See this section for more details on how to configure this property.
include
Type: string[]|string
This option takes a minimatch pattern or an array of minimatch patterns and only transforms files with filenames that the pattern matches.
exclude
Type: string[]|string
This option takes a minimatch pattern or an array of minimatch patterns and only transforms files with filenames that the pattern doesn't match.
transpileOnly
Type: boolean
If this option is true
, diagnostics won't be generated. This will improve performance since Typescript but ignores all syntactical and semantic errors or warnings that may arise.
fileSystem
Optionally the FileSystem to use. This is useful for example when you want to provide a virtual FileSystem to read from or write to.
hook
Use this property to get hooks into the internals of rollup-plugin-ts
.
See this section for more details.
Typescript and Babel are powerful tools in their own right. Combined with Rollup, they become even more powerful. To provide a seamless experience, Rollup always take precedence when conflicts arise. As a natural consequence of this, some options provided to Typescript and Babel will be ignored or overridden.
The following CompilerOptions from a tsconfig
will be ignored:
Property | Reason |
---|---|
outDir | Rollup, not Typescript, will decide where to emit chunks. |
outFile | This option produces flat output and only works with the module formats AMD and SystemJS. Rollup will be the decider of how to split code. |
sourceMap | Typescript will always be instructed to produce SourceMaps. Rollup then decides whether or not to include them (and if they should be inlined). |
inlineSourceMap | Typescript will always be instructed to produce SourceMaps. Rollup then decides whether or not to include them (and if they should be inlined). |
inlineSources | Since inlineSourceMap is ignored, this option won't take effect. |
importHelpers | Helpers will always be imported. This makes it possible for Rollup to code-split properly and share Typescript helpers across chunks. |
moduleResolution | Node-module resolution will always be used. This is required for importHelpers to work and in general, to make Typescript able to resolve external libraries. Note that you still need to add the nodeResolve plugin in order to include external libraries within your bundle unless allowJs is true within your tsconfig |
noEmit | Typescript should always be able to emit assets, but those will be delegated to Rollup. |
noEmitOnError | See above. |
emitDeclarationOnly | See above. |
noEmitHelpers | Typescript should always be able to emit helpers, since the importHelpers option is forced |
noResolve | Typescript should always be able to resolve things. Otherwise, compilation might break. |
watch | Rollup, not Typescript, will watch files if run in watch mode. Efficient caching will still be used for optimum performance. |
preserveWatchOutput | See above |
The following additional options will also be ignored:
Property | Reason |
---|---|
include | Rollup itself will decide which files to include in the transformation process based on your code. This plugin itself takes a include property which you should use instead if you want to explicitly allow specific files or globs. |
exclude | See above. |
The following Babel options will be ignored:
Property | Reason |
---|---|
sourceMaps | Babel will always be instructed to produce SourceMaps. Rollup then decides whether or not to include them (and if they should be inlined). |
cwd | The cwd option provided to the plugin will always be used. |
include | Rollup itself will decide which files to include in the transformation process based on your code. This plugin itself takes a include property which you should use instead if you want to explicitly allow specific files or globs. |
exclude | See above |
ignore | See above |
only | See above |
sourceType | Will always use module . Rollup will then decide what to do based on the output format |
If you decide to use Babel as the transpiler with the transpiler
plugin option set to "babel"
, some best-practice default plugins and presets will be applied such that you don't have to configure anything on your own.
By default, the plugin will conditionally apply the @babel/preset-env
preset if a Browserslist is provided or located, as well as plugins for handling shipped proposals. And, the @babel/plugin-runtime
plugin will be used for extracting Babel helpers and reusing them across your chunks to avoid code duplication.
If you provide these presets or plugins yourself through the found or provided Babel config, your config options will take precedence.
Here's table with a full overview of the specifics:
Preset/Plugin | Condition | Reason |
---|---|---|
@babel/preset-env | A Browserslist is provided or found automatically, and you don't provide this preset yourself within your Babel config | This preset enables you to base your syntax transformations on the specific browsers/environment you want your application or library to target. It will "Just Work" |
@babel/plugin-transform-runtime | You don't provide this plugin yourself within your Babel config | Depending on your configuration, async functions may be rewritten to use Regenerator Runtime, and there may be one or more Babel helpers injected within your code. @babel/plugin-runtime allows this plugin to avoid duplicating these helpers, and instead make them shared across Chunks seamlessly via Rollup. |
@babel/plugin-proposal-object-rest-spread | You don't provide this plugin yourself within your Babel config | This plugin is needed in order to enable parsing Object Rest/Spread syntax, something that is a Stage 4 proposal for ECMAScript and will be part of ES2018. |
@babel/plugin-proposal-async-generator-functions | You don't provide this plugin yourself within your Babel config | This plugin is needed in order to support Asynchronous Iteration syntax, something that is a Stage 4 proposal for ECMAScript and will be part of ES2018. |
@babel/plugin-proposal-optional-catch-binding | You don't provide this plugin yourself within your Babel config | This plugin is needed in order to support Optional Catch Binding syntax, something that is a Stage 4 proposal for ECMAScript and will be part of ES2019. |
@babel/plugin-proposal-unicode-property-regex | You don't provide this plugin yourself within your Babel config | This plugin is needed in order to support RegExp Unicode Property Escapes syntax, something that is a Stage 4 proposal for ECMAScript and will be part of ES2018. |
@babel/plugin-proposal-json-strings | You don't provide this plugin yourself within your Babel config | This plugin is needed in order to support JSON superset syntax, something that is a Stage 4 proposal for ECMAScript and will be part of ES2019. |
Do you want to contribute? Awesome! Please follow these recommendations.
Frederik Wessberg Twitter: @FredWessberg Github: @wessberg Lead Developer |
Become a backer and get your name, avatar, and Twitter handle listed here.
Absolutely, even with Declaration files. Things will work seamlessly.
The Typescript compiler, while extremely powerful, has the restriction that it can only target a specific ECMAScript version. In reality, browsers and other ECMAScript environments has varying support for newer language features. Some browsers support even those features that haven't been publicized yet, while others support only parts of the latest language features.
In effect, a browser may support a lot of modern features such as classes and proper lexical scoping, but lack others. With Typescript, it's "all-or-nothing": If you want to support a Browser with partial support, you must target the latest publicized ECMAScript version that the browser fully supports.
Babel, on the other hand, is far more granular in its design and applies syntax transformations on a feature-by-feature basis.
Combined with something like @babel/preset-env
, individual transformations can be applied for only those language features that are missing.
This means that you can use things like classes and lexical scoping in browsers that otherwise doesn't fully support all of the ES2015 specification.
Babel has recently received support for parsing and transforming Typescript. It would be intriguing to just use Babel for everything. However, there are significant caveats:
The Babel compiler works on a file-by-file basis, meaning it is simple to use and reason about, whereas the Typescript compiler works with Programs, or in other words sets of related SourceFiles. This gives Typescript the advantage over Babel that it has a greater understanding of your codebase in general and can understand your types across files. In the context of this plugin, this enables Typescript to do things that you simply wouldn't be able to do with the Typescript plugin for Babel:
.d.ts
) files and Typescript declaration map (.d.ts.map
) files.const enums
and all other files that will require type information.First, Typescript will be used for:
.d.ts
) files and Typescript declaration map (.d.ts.map
) files.Babel will then be used for all other syntax transformation from then on, depending on the combination of default, provided, and forced presets and plugins.
MIT © Frederik Wessberg (@FredWessberg) (Website)
FAQs
A TypeScript Rollup plugin that bundles declarations, respects Browserslists, and enables seamless integration with transpilers such as babel and swc
The npm package @wessberg/rollup-plugin-ts receives a total of 832 weekly downloads. As such, @wessberg/rollup-plugin-ts popularity was classified as not popular.
We found that @wessberg/rollup-plugin-ts demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.
Security News
Research
Socket's threat research team has detected five malicious npm packages targeting Roblox developers, deploying malware to steal credentials and personal data.