question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using together with Babel plugins and `emitDeclarationOnly` overwrites output files with no content

See original GitHub issue

Hey, thanks for this great plugin. Always use it but this time I have to compile the code with babel and just use this for declarations and it doesn’t work for that.

What happens and why it is wrong

Environment

Using babel to compile files since I need to run code through a plugin:

babel({ extensions, babelHelpers: 'bundled', exclude: 'node_modules/**' }),
typescript(),

Tried setting emitDeclarationOnly in tsconfig.json and above e.g.:

typescript({
    tsconfigOverride: {
      compilerOptions: {
        emitDeclarationOnly: true,
      },
    },
  })

Also tried putting typescript() before babel() and it still somehow overrides the output files.

Versions
 rollup: ^2.45.2 => 2.45.2
rollup-plugin-typescript2: ^0.30.0 => 0.30.0
typescript: ^4.2.4 => 4.2.4

rollup.config.js

/* eslint-env node */
import replace from '@rollup/plugin-replace'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import { babel } from '@rollup/plugin-babel'
import { terser } from 'rollup-plugin-terser'
import minifyHTML from 'rollup-plugin-minify-html-literals'
import typescript from 'rollup-plugin-typescript2'

const globals = {}
const external = Object.keys(globals)
const isProd = process.env.NODE_ENV === 'production'
const extensions = ['.js', '.jsx', '.ts', '.tsx']

const output = [
  {
    file: 'dist/index.js',
    format: 'esm',
    globals,
  },
]

if (isProd) {
  output.push({
    name: 'myAppName',
    file: 'dist/index.umd.js',
    format: 'umd',
    globals,
  })
}

export default {
  input: 'src/index.ts',
  output,
  external,
  plugins: [
    minifyHTML(),
    replace({
      preventAssignment: true,
      values: {
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
      },
    }),
    commonjs(),
    nodeResolve({
      extensions,
      browser: true,
    }),
    babel({ extensions, babelHelpers: 'bundled', exclude: 'node_modules/**' }),
    typescript({
      tsconfigOverride: {
        compilerOptions: {
          emitDeclarationOnly: true,
        },
      },
    }),
    process.env.NODE_ENV === 'production' &&
      terser({
        module: true,
        output: {
          comments: false,
        },
      }),
  ],
}

#### .babelrc.json

{
  "presets": ["@babel/preset-typescript", "babel-preset-solid"]
}

tsconfig.json

{
  "compilerOptions": {
    "target": "es2018",
    "module": "esnext",
    "lib": ["es2018", "dom", "dom.iterable"],
    "declaration": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "emitDeclarationOnly": true,
    "esModuleInterop": true,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "forceConsistentCasingInFileNames": true,
    "jsx": "preserve",
    "jsxImportSource": "solid-js"
  },
  "include": ["src"],
  "exclude": ["node_modules"]
}

plugin output with verbosity 3

plugin output with verbosity 3:
src/index.ts → dist/index.js, dist/index.umd.js...
rpt2: built-in options overrides: {
    "noEmitHelpers": false,
    "importHelpers": true,
    "noResolve": false,
    "noEmit": false,
    "inlineSourceMap": false,
    "outDir": "/Users/infensus/Projects/lightfin/packages/core/node_modules/.cache/rollup-plugin-typescript2/placeholder",
    "moduleResolution": 2,
    "allowNonTsExtensions": true
}
rpt2: parsed tsconfig: {
    "options": {
        "target": 5,
        "module": 99,
        "lib": [
            "lib.es2018.d.ts",
            "lib.dom.d.ts",
            "lib.dom.iterable.d.ts"
        ],
        "declaration": true,
        "outDir": "/Users/infensus/Projects/lightfin/packages/core/node_modules/.cache/rollup-plugin-typescript2/placeholder",
        "rootDir": "/Users/infensus/Projects/lightfin/packages/core/src",
        "strict": true,
        "emitDeclarationOnly": true,
        "esModuleInterop": true,
        "moduleResolution": 2,
        "allowSyntheticDefaultImports": true,
        "experimentalDecorators": true,
        "forceConsistentCasingInFileNames": true,
        "jsx": 1,
        "jsxImportSource": "solid-js",
        "configFilePath": "/Users/infensus/Projects/lightfin/packages/core/tsconfig.json",
        "noEmitHelpers": false,
        "importHelpers": true,
        "noResolve": false,
        "noEmit": false,
        "inlineSourceMap": false,
        "allowNonTsExtensions": true
    },
    "fileNames": [
        "/Users/infensus/Projects/lightfin/packages/core/src/index.ts",
        "/Users/infensus/Projects/lightfin/packages/core/src/components/grid.tsx",
        "/Users/infensus/Projects/lightfin/packages/core/src/components/index.ts",
        "/Users/infensus/Projects/lightfin/packages/core/src/components/registerGridElements.ts",
        "/Users/infensus/Projects/lightfin/packages/core/src/utils/css.ts",
        "/Users/infensus/Projects/lightfin/packages/core/src/utils/index.ts"
    ],
    "typeAcquisition": {
        "enable": false,
        "include": [],
        "exclude": []
    },
    "raw": {
        "compilerOptions": {
            "target": "es2018",
            "module": "esnext",
            "lib": [
                "es2018",
                "dom",
                "dom.iterable"
            ],
            "declaration": true,
            "outDir": "./dist",
            "rootDir": "./src",
            "strict": true,
            "emitDeclarationOnly": true,
            "esModuleInterop": true,
            "moduleResolution": "node",
            "allowSyntheticDefaultImports": true,
            "experimentalDecorators": true,
            "forceConsistentCasingInFileNames": true,
            "jsx": "preserve",
            "jsxImportSource": "solid-js"
        },
        "include": [
            "src"
        ],
        "exclude": [
            "node_modules"
        ],
        "compileOnSave": false
    },
    "errors": [],
    "wildcardDirectories": {
        "/users/infensus/projects/lightfin/packages/core/src": 1
    },
    "compileOnSave": false
}
rpt2: typescript version: 4.2.4
rpt2: tslib version: 2.1.0
rpt2: rollup version: 2.45.2
rpt2: rollup-plugin-typescript2 version: 0.30.0
rpt2: plugin options:
{
    "verbosity": 3,
    "tsconfigOverride": {
        "compilerOptions": {
            "emitDeclarationOnly": true
        }
    },
    "check": true,
    "clean": false,
    "cacheRoot": "/Users/infensus/Projects/lightfin/packages/core/node_modules/.cache/rollup-plugin-typescript2",
    "include": [
        "*.ts+(|x)",
        "**/*.ts+(|x)"
    ],
    "exclude": [
        "*.d.ts",
        "**/*.d.ts"
    ],
    "abortOnError": true,
    "rollupCommonJSResolveHack": false,
    "useTsconfigDeclarationDir": false,
    "transformers": [],
    "tsconfigDefaults": {},
    "objectHashIgnoreUnknownHack": false,
    "cwd": "/Users/infensus/Projects/lightfin/packages/core",
    "typescript": "version 4.2.4"
}
rpt2: rollup config:
{
    "external": [],
    "input": "src/index.ts",
    "plugins": [
        {
            "name": "minify-html-literals"
        },
        {
            "name": "replace"
        },
        {
            "name": "commonjs"
        },
        {
            "name": "node-resolve"
        },
        {
            "name": "babel"
        },
        {
            "name": "rpt2"
        },
        {
            "name": "terser"
        },
        {
            "name": "stdin"
        }
    ],
    "output": [
        {
            "file": "dist/index.js",
            "format": "esm",
            "globals": {},
            "plugins": []
        },
        {
            "file": "dist/index.umd.js",
            "format": "umd",
            "globals": {},
            "name": "lightfin",
            "plugins": []
        }
    ]
}
rpt2: tsconfig path: /Users/infensus/Projects/lightfin/packages/core/tsconfig.json
rpt2: included:
[
    "*.ts+(|x)",
    "**/*.ts+(|x)"
]
rpt2: excluded:
[
    "*.d.ts",
    "**/*.d.ts"
]

dist/index.js becomes empty if typescript plugin is loaded and dist/index.umd.js just has a stub - var e;e=function(){},"function"==typeof define&&define.amd&&define(e);

Thanks!

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:9
  • Comments:8 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
tushar1998commented, Nov 22, 2021

Doesnt Work for me either with babel 7

    nodeResolve({
      browser: true,
    }),
    commonjs({
      include: /node_modules/,
    }),
    babel({
      exclude: /node_modules/,
      babelHelpers: 'runtime',
    })
// package.json
"rollup-plugin-typescript2": "^0.31.0"
"rollup": "2.59.0",

Output:

./src/index.ts → lib/index.cjs.js, lib/index.ems.js, lib/index.umd.js...
(!) Generated empty chunks
index, index, index
created lib/index.cjs.js, lib/index.ems.js, lib/index.umd.js in 1.8s

1reaction
agilgur5commented, Jun 23, 2022

root cause analysis

So I dug a bit more into this and found an interesting result when logging out output from this line while having emitDeclarationOnly set:

{
  outputFiles: [
    {
      name: '<project root>/node_modules/.cache/rollup-plugin-typescript2/placeholder/index.d.ts.map',
      writeByteOrderMark: false,
      text: '{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,UAE/C;AAED,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAA"}'
    },
    {
      name: '<project root>/node_modules/.cache/rollup-plugin-typescript2/placeholder/index.d.ts',
      writeByteOrderMark: false,
      text: 'export default function sum(a: number, b: number): number;\r\n' +
        "export { default as difference } from './difference';\r\n" +
        '//# sourceMappingURL=index.d.ts.map'
    }
  ],
  emitSkipped: false,
  diagnostics: [],
  exportedModulesFromDeclarationEmit: undefined
}

Some key pieces:

  1. Only the declaration and declaration map are here (declaration: true and declarationMap: true, respectively), but notably there is no JS code returned from the TS Compiler (the LanguageService API’s getEmitOutput method, to be specific). This is why emitDeclarationOnly causes an empty chunk with “no content” to be returned to Rollup (and subsequent plugins).
  2. emitSkipped is false. This is an important difference from #338, as if it were true, rpt2 would error out instead (this what is used to determine if a fatal error occurred).

feature incoming!

Changing the code to instead return undefined in the case of emitDeclarationOnly will allow other plugins on the chain to process/transform/compile the TS. So there is indeed a missing feature needed to support emitDeclarationOnly! (note that rpt2 was used before the emitDeclarationOnly compilerOption even existed)

I wrote up the code for this and already tested it and confirmed that is working! It’s actually a very small feature that opens up quite a bit of new use-cases (which is why I wanted to prioritize it after joining on as a maintainer!) 🙂
For instance, you can use with Babel as mentioned here, but also with other tools that can compile TS like ESBuild and swc etc. So rpt2 does the type-checking and declaration generation, while Babel (with its various plugins, such as babel-plugin-typescript-to-proptypes as the use-case downstream in TSDX asks for) or others do the TS -> JS compilation (or JS -> JS transpilation when allowJs). Note that rpt2 will have to come before those plugins in the chain (as I mentioned 2 comments above), so that it actually reads TS and produces declarations based on source TS and not compiled JS that is lacking types.

I’ll have a PR out for this tomorrow (heading to bed now) 🚀 EDIT: see #366

Read more comments on GitHub >

github_iconTop Results From Across the Web

Options - Babel
Placement: Allowed in Babel's programmatic options, or inside of the loaded configFile . A programmatic option will override a config file one. By...
Read more >
TSConfig Reference - Docs on every TSConfig option
Intro to the TSConfig Reference. A TSConfig file in a directory indicates that the directory is the root of a TypeScript or JavaScript...
Read more >
@rollup/plugin-typescript - npm
A picomatch pattern, or array of patterns, which specifies the files in the build the plugin should ignore. By default no files are...
Read more >
Codemods with Babel Plugins - Egghead.io
We want to use vanilla Babel to write a custom plugin that will transform our code ... Egghead is no longer just for...
Read more >
rollup-plugin-ts | Yarn - Package Manager
A TypeScript Rollup plugin that bundles declarations, respects Browserslists, and enables seamless integration with transpilers such as babel and swc.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found