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

[How To] Use with rollup #106

Closed
daniloribeiro00 opened this issue Jun 23, 2023 · 14 comments
Closed

[How To] Use with rollup #106

daniloribeiro00 opened this issue Jun 23, 2023 · 14 comments
Labels
question Further information is requested

Comments

@daniloribeiro00
Copy link

I have a library that relies on ttypescript with rollup and, since it's now officially deprecated, I'm looking into a solution.

The way I use ttypescript is like it's docs (https://github.com/cevek/ttypescript#rollup), with rollup-plugin-typescript2

// rollup.config.js
import ttypescript from 'ttypescript'
import tsPlugin from 'rollup-plugin-typescript2'

export default {
    // ...
    plugins: [
        // ...
        tsPlugin({
            typescript: ttypescript
        })
    ]
}

Since ts-patch docs says it is "Fully compatible with legacy ttypescript projects" I tried to just swap them but it didn't work.
Maybe I'm missing something...

Can anyone help please?

@ryanbas21
Copy link

@daniloribeiro00 I'm looking into this as well, i'll update if i solve anything today

@nonara
Copy link
Owner

nonara commented Jun 23, 2023

Hi all. You should be able to specify typescript as ts-patch/compiler.

The following should work. Please let me know if it does:

// rollup.config.js
import tspCompiler from 'ts-patch/compiler'
import tsPlugin from 'rollup-plugin-typescript2'

export default {
    // ...
    plugins: [
        // ...
        tsPlugin({
            typescript: tspCompiler
        })
    ]
}

@nonara nonara changed the title Can't use as Rollup plugin [Question] How to use with rollup Jun 23, 2023
@nonara nonara added the question Further information is requested label Jun 23, 2023
@nonara nonara changed the title [Question] How to use with rollup [How To] Use with rollup Jun 23, 2023
@nonara
Copy link
Owner

nonara commented Jun 27, 2023

Can either of you confirm that this worked for you?

@ryanbas21
Copy link

I was using vite and it didnt exactly work for but I also had to pivot off of this so I was unable to really dig into it. I don't recall why it wasnt working so i can't really help too much as i moved off this path

Sorry I can't be of more help.

@Lewage59
Copy link

Lewage59 commented Jul 5, 2023

This worked for me, but need to be in the commonjs env. So this my method

import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);
const tspCompiler = require('ts-patch/compiler');

export default {
    // ...
    plugins: [
        // ...
        tsPlugin({
            typescript: tspCompiler
        })
    ]
}

@daniloribeiro00
Copy link
Author

daniloribeiro00 commented Jul 12, 2023

Sorry for the delay... but it didn't work as expected...

First: I couldn't import the directory 'ts-patch/compiler' itself as I got the following message:

[!] Error: Directory import 'ts-patch\compiler' is not supported resolving ES modules imported from C:\Users\danilo.ribeiro\Documents\Projetos\design-system-ui\build\rollup.config.mjs
Did you mean to import ts-patch/compiler/typescript.js?

So I did what it asked and imported 'ts-patch/compiler/typescript.js' instead. But I got this other message:

[!] (plugin rpt2) RollupError: transformerFn is not a function

@nonara Looks like you already know about it (#104) but it was not clear to me how to solve it.

Can you please help me with this?

Thanks in advance!

@nonara
Copy link
Owner

nonara commented Jul 12, 2023

@daniloribeiro00 Thanks for the response. #104 is unrelated. That was a bug in a beta version. (#104 was an issue in the way the transformer was exported. Was no longer ttypescript / ts-patch compliant)

If you're using ESM, you should be able to use the solution in the comment by @Lewage59 above yours

@daniloribeiro00
Copy link
Author

daniloribeiro00 commented Jul 12, 2023

@nonara I've tried it, but it returns the same error

@nonara
Copy link
Owner

nonara commented Jul 12, 2023

transformerFn is not a function indicates a problem with the default export from whatever your plugin's root file is.

In the other issue you mentioned, that is what was happening there as well.

The problem was the plugin in the package he was trying to use was not exporting a default export which was a tspatch compatible entry function.

@daniloribeiro00
Copy link
Author

That's weird. It worked with ttypescript and TS v4.7. The code I'm working is a Vue components library. I built it based on a boilerplate I found online about 2 years ago and I'm not sure how it works.
Maybe if I share the code you could help me solve this, please?

// rollup.config.mjs

import alias from '@rollup/plugin-alias';
import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import terser from '@rollup/plugin-terser';
import fs from 'fs';
import minimist from 'minimist';
import path from 'path';
import PostCSS from 'rollup-plugin-postcss';
import typescript from 'rollup-plugin-typescript2';
import vue from 'rollup-plugin-vue';
import tspCompiler from 'ts-patch/compiler/typescript.js';
// import ttypescript from 'ttypescript';
import * as url from 'url';

import * as babelConfig from '../babel.config.js';

const __dirname = url.fileURLToPath(new URL('.', import.meta.url));

// Get browserslist config and remove ie from es build targets
const esbrowserslist = fs
  .readFileSync('./.browserslistrc')
  .toString()
  .split('\n')
  .filter((entry) => entry && entry.substring(0, 2) !== 'ie');

// Extract babel preset-env config, to combine with esbrowserslist
const babelPresetEnvConfig = babelConfig.presets.filter(
  (entry) => entry[0] === '@babel/preset-env'
)[0][1];

const argv = minimist(process.argv.slice(2));

const projectRoot = path.resolve(__dirname, '..');

// Base rollup config
const baseConfig = {
  input: 'src/entry.ts',
  plugins: {
    preVue: [
      alias({
        entries: [
          {
            find: '@',
            replacement: `${path.resolve(projectRoot, 'src')}`,
          },
        ],
      }),
    ],
    replace: {
      'process.env.NODE_ENV': JSON.stringify('production'),
      preventAssignment: true,
    },
    vue: {},
    postVue: [
      resolve({
        extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
      }),
      // Process only `<style module>` blocks.
      PostCSS({
        modules: {
          generateScopedName: '[local]___[hash:base64:5]',
        },
        include: /&module=.*\.css$/,
      }),
      // Process all `<style>` blocks except `<style module>`.
      PostCSS({ include: /(?<!&module=.*)\.css$/ }),
      commonjs(),
    ],
    babel: {
      exclude: 'node_modules/**',
      extensions: ['.js', '.jsx', '.ts', '.tsx', '.vue'],
      babelHelpers: 'bundled',
    },
  },
  // New setting since Rollup v3
  strictDeprecations: true,
  makeAbsoluteExternalsRelative: true,
  preserveEntrySignatures: 'strict',
  output: {
    esModule: true,
    generatedCode: {
      reservedNamesAsProps: false,
    },
    interop: 'compat',
    systemNullSetters: false,
  },
};

// ESM/UMD/IIFE shared settings: externals
// Refer to https://rollupjs.org/guide/en/#warning-treating-module-as-external-dependency
const external = [
  // list external dependencies, exactly the way it is written in the import statement.
  'vue',
];

// UMD/IIFE shared settings: output.globals
// Refer to https://rollupjs.org/guide/en#output-globals for details
const globals = {
  // Provide global variable names to replace your external imports
  vue: 'Vue',
};

// Customize configs for individual targets
const buildFormats = [];
if (!argv.format || argv.format === 'es') {
  const esConfig = {
    ...baseConfig,
    input: 'src/entry.esm.ts',
    external,
    output: {
      file: 'dist/design-system-ui.esm.js',
      format: 'esm',
      exports: 'named',
    },
    plugins: [
      replace(baseConfig.plugins.replace),
      ...baseConfig.plugins.preVue,
      vue(baseConfig.plugins.vue),
      ...baseConfig.plugins.postVue,
      // Only use typescript for declarations - babel will
      // do actual js transformations
      typescript({
        typescript: tspCompiler,
        useTsconfigDeclarationDir: true,
        emitDeclarationOnly: true,
      }),
      babel({
        ...baseConfig.plugins.babel,
        presets: [
          [
            '@babel/preset-env',
            {
              ...babelPresetEnvConfig,
              targets: esbrowserslist,
            },
          ],
        ],
      }),
    ],
  };
  buildFormats.push(esConfig);
}

if (!argv.format || argv.format === 'cjs') {
  const umdConfig = {
    ...baseConfig,
    external,
    output: {
      compact: true,
      file: 'dist/design-system-ui.ssr.js',
      format: 'cjs',
      name: 'DesignSystemUi',
      exports: 'auto',
      globals,
    },
    plugins: [
      replace(baseConfig.plugins.replace),
      ...baseConfig.plugins.preVue,
      vue(baseConfig.plugins.vue),
      ...baseConfig.plugins.postVue,
      babel(baseConfig.plugins.babel),
    ],
  };
  buildFormats.push(umdConfig);
}

if (!argv.format || argv.format === 'iife') {
  const unpkgConfig = {
    ...baseConfig,
    external,
    output: {
      compact: true,
      file: 'dist/design-system-ui.min.js',
      format: 'iife',
      name: 'DesignSystemUi',
      exports: 'auto',
      globals,
    },
    plugins: [
      replace(baseConfig.plugins.replace),
      ...baseConfig.plugins.preVue,
      vue(baseConfig.plugins.vue),
      ...baseConfig.plugins.postVue,
      babel(baseConfig.plugins.babel),
      terser({
        output: {
          ecma: 5,
        },
      }),
    ],
  };
  buildFormats.push(unpkgConfig);
}

export default buildFormats;
// entry.ts

// iife/cjs usage extends esm default export - so import it all
import plugin, * as components from '@/entry.esm';

// Attach named exports directly to plugin. IIFE/CJS will
// only expose one global var, with component exports exposed as properties of
// that global var (eg. plugin.component)
type NamedExports = Exclude<typeof components, 'default'>;
type ExtendedPlugin = typeof plugin & NamedExports;
Object.entries(components).forEach(([componentName, component]) => {
  if (componentName !== 'default') {
    const key = componentName as Exclude<keyof NamedExports, 'default'>;
    const val = component as Exclude<ExtendedPlugin, typeof plugin>;
    (plugin as ExtendedPlugin)[key] = val;
  }
});

export default plugin;
// entry.esm.ts

import { App, Plugin } from 'vue';

// Import vue components
import * as components from '@/lib-components/index';

// install function executed by Vue.use()
const install: Exclude<Plugin['install'], undefined> = function installDesignSystemUi(app: App) {
  Object.entries(components).forEach(([componentName, component]) => {
    app.component(componentName, component);
  });
};

// Create module definition for Vue.use()
export default install;

// To allow individual component use, export components
// each can be registered via Vue.component()
export * from '@/lib-components/index';

@nonara
Copy link
Owner

nonara commented Jul 18, 2023

I'm pretty badly backlogged, but if you can make a repository with a minimal reproduction of the issue (using those files presumably) that i can clone, I will take a look.

Make sure to use the createRequire method and import the compiler as mentioned in the note above (from ts-patch/compiler), since you're importing into an esm js file.

@daniloribeiro00
Copy link
Author

I've tried createRequire as you suggested but I keep getting the same message.

Here is the repository: https://github.com/daniloribeiro00/ts-patch-repro

Thanks by the help! :)

@nonara
Copy link
Owner

nonara commented Jul 20, 2023

@daniloribeiro00 Thanks for taking the time.

Turns out it uncovered a weird flaw in one of the last remaining pieces of legacy ttypescript code. When I was modifying that recently, I trusted the typechecker & a variable name which indicated it could only be a certain type (function-based), when in fact there was a possibility that it could also be another (object-based). Odd that the typechecker didn't catch it!

In any case, it's corrected and should work now. To be sure, wipe node_modules and reinstall.

Associated issue:

@nonara nonara pinned this issue Jul 20, 2023
@nonara nonara closed this as completed Jul 20, 2023
@daniloribeiro00
Copy link
Author

Works like a charm! Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants