javascripttypescriptrollupjslernamonorepo

Building Typescript: [!] Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)


I've encountered problem building typescript packages with rollup inside lerna managed monorepo.

Error:

lerna ERR! rollup --config ../../rollup.config.js stderr:
loaded ../../rollup.config.js with warnings
(!) Unused external imports
terser imported from external module 'rollup-plugin-terser' but never used

index.ts → dist/esm...
[!] Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
../mokui-base/component.ts (3:7)
1: const root = Symbol("root");
2: 
3: export type Component<T extends object = {}> = T & {
          ^
4:         [root]: Element;
5:         attach(element: Element): Component<T>;
Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
    at error (/****/****/code/js/mokui/node_modules/rollup/dist/rollup.js:5351:30)
    at Module.error (/****/****/code/js/mokui/node_modules/rollup/dist/rollup.js:9643:9)
    at tryParse (/****/****/code/js/mokui/node_modules/rollup/dist/rollup.js:9552:16)
    at Module.setSource (/****/****/code/js/mokui/node_modules/rollup/dist/rollup.js:9868:33)
    at Promise.resolve.catch.then.then.then (/****/****/code/js/mokui/node_modules/rollup/dist/rollup.js:12148:20)


lerna ERR! rollup --config ../../rollup.config.js exited 1 in '@moki.codes/mokui-header'

Error points at "export type" tokens which is well... confusing, how come typescript doesn't understand own constructs i am not sure.

One will be able to reproduce error by cloning repository and running yarn build:packages @master branch.

Interestingly enough mokui-base package which defines Component builds just fine by itself, giving the error above on build only when one depend on it like i do inside the mokui-header. Reproducible by adding

if (process.env.LERNA_PACKAGE_NAME === "@moki.codes/mokui-header")
    process.exit(0);

at the top of the rollup.config.js and running yarn build:packages.

I also have another build target "dev" one can try with yarn build:dev which builds from stories/index.ts, and serves at localhost:3000. It is relevant to the question because there, mokui-header Header builds just fine depending on the mokui-base Component, Header factory is used inside index.ts and gives no errors, works as intented and provides defined behavior.

My first instinct was to opt out of the cjs build because thats the main difference between two builds(build:packages and build:dev), but that didn't make any difference, so that leaves with the @organization/package resolution problem i guess, i am not sure... not like i know where to go from there if that's the case. Removing export at export type Component =... inside component.ts source gets rid of the error, but of course that spawns the new error inside the mokui-header HeaderComponent complaining that Component is a value but used as type, because well... there is no Component type export to consume anymore.

So yeah, if you have any ideas where should i go from here or know exactly how i should go about building typescript package, which depends on the other sibling one please do share them.

I am sorry if i come off as rude but please don't recommend me opting out of the custom build and use preconfigured boilerplate or something of that sort.

Thanks in advance!


Solution

  • In case anyone encounters the same problem, below i am providing solution:

    When one attempts to build each separate package inside the monorepo, rollup attempts to resolve @organization/package-name and include it in the build. You don't want that, so to avoid it upon building each package i am parsing package.json, extracting the dependencies field's keys, then to check against them inside the callback one can provide inside rollup config's external field. This will produce the desired outcome.

    import json from "rollup-plugin-json";
    
    const pkg = process.env.LERNA_PACKAGE_NAME &&
              require(`${process.env.LERNA_PACKAGE_NAME}/package.json`);
    
    const dependencies = ({ dependencies }) => Object.keys(dependencies || {});
    
    const pkgdependencies = dependencies(pkg);
    
    /* exported rollup configuration */
    const config = {
        /* your config goes here... */
        /* id is the source name if list of dependencies includes
         * id source name, then mark it as external,
         */
        external: id => pkgdependencies.includes(id)
    };
    
    export default config;