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

Document tsconfig File for Plop Usage in TS #192

Closed
Vanuan opened this issue Dec 17, 2019 · 29 comments
Closed

Document tsconfig File for Plop Usage in TS #192

Vanuan opened this issue Dec 17, 2019 · 29 comments

Comments

@Vanuan
Copy link

Vanuan commented Dec 17, 2019

How to reproduce

  1. yarn install plop
  2. Create a perfectly valid plopfile.ts:

import { NodePlopAPI, AddActionConfig } from 'plop';

export default function generator(plop: NodePlopAPI): void {
  ...
}
  1. yarn run plop

Expected behavior

plop prints a user prompt, generates files

Actual behavior

$ plop
/src/plopfile.ts:1
import { NodePlopAPI, AddActionConfig } from 'plop';
^^^^^^

SyntaxError: Cannot use import statement outside a module

Versions

Node version: 12.3.0
Plop version: 2.5.3

@Vanuan
Copy link
Author

Vanuan commented Dec 17, 2019

Do I need to pass some typescript loader here?

@Vanuan
Copy link
Author

Vanuan commented Dec 17, 2019

Ok, if node can't load ES6 modules, maybe I can use require syntax?

exports.__esModule = true;

const Plop = require 'plop';
function generator(plop: Plop.NodePlopAPI): void {
}
exports["default"] = generator;

Nope, I can't:

/src/plopfile.ts:6
function generator(plop: NodePlopAPI): void {
                       ^

SyntaxError: Unexpected token ':'
    at Module._compile (internal/modules/cjs/loader.js:892:18)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
    at Module.load (internal/modules/cjs/loader.js:812:32)
    at Function.Module._load (internal/modules/cjs/loader.js:724:14)
    at Module.require (internal/modules/cjs/loader.js:849:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at nodePlop (/src/node_modules/node-plop/lib/node-plop.js:268:5)
    at Liftoff.run (/src/node_modules/plop/src/plop.js:32:15)
    at Liftoff.execute (/src/node_modules/liftoff/index.js:203:12)
    at module.exports (/src/node_modules/flagged-respawn/index.js:51:3)

@Vanuan
Copy link
Author

Vanuan commented Dec 17, 2019

What am I missing here? Does Plop support typescript?

@Vanuan
Copy link
Author

Vanuan commented Dec 18, 2019

Renamed to plopfile.js and removes TS syntax.

@Vanuan Vanuan closed this as completed Dec 18, 2019
@amwmedia
Copy link
Member

@cspotcode @crutchcorn Any ideas here? This typescript stuff is kind of your baby 😉

@cspotcode
Copy link
Contributor

@Vanuan tl;dr install typescript and ts-node as dependencies. ts-node allows require()ing TypeScript files directly, which plop will use to load your plopfile.ts. It will honor your tsconfig.json, so if you have one of those, make sure it is configured correctly for node. (For example, "module": "ESNext" will cause problems)

@amwmedia this is a more general Liftoff issue when using any sort of loader, not just TypeScript. (babel, coffeescript, etc)

Looks like Liftoff attempts to install any of the loaders declared in require('interpret').jsVariants and fires events when this fails. You might want plop to either terminate or at least log something friendly on those events.
https://github.com/js-cli/js-liftoff/blob/master/README.md#onloaderfailure-functionname-err-
https://github.com/js-cli/js-liftoff/blob/master/lib/register_loader.js#L10-L16

The plop docs can be updated to mention that TypeScript requires installing ts-node and typescript as dependencies. TypeScript users will often already be doing this, but can't hurt to be explicit. If you want to be more generic, you could say something like "if you're using a compiled language, you'll need to install and configure a loader supported by https://www.npmjs.com/package/interpret"

@amwmedia
Copy link
Member

Thanks for taking a look at this. It looks like we do need to bolster documentation in this area a bit. 👍

@jednano
Copy link
Contributor

jednano commented Mar 3, 2020

Seeing as everybody isn't using TypeScript, perhaps a peerDependency of ts-node is not appropriate, but an optionalDependency might be?

@mrlubos
Copy link

mrlubos commented Sep 7, 2020

Hey @cspotcode, I am running into the same issue using create-react-app TypeScript boilerplate. Any advice? I believe that boilerplate already uses all required dependencies.

@FDiskas
Copy link
Contributor

FDiskas commented Nov 23, 2020

Just a note: typesript.json should include

"module": "CommonJS",

@Statfine
Copy link

if you used ts, you may need separate configuration tsconfig.json

"generate": "cross-env TS_NODE_PROJECT='./internals/ts-node.tsconfig.json' plop --plopfile ./internals/plopfile.ts"


ts-node.tsconfig.json
{
    "compilerOptions": {
        "esModuleInterop": true,
        "module": "commonjs",
        "moduleResolution": "node",
        "noEmit": true,
        "allowSyntheticDefaultImports": true
    }
}


``

@cspotcode
Copy link
Contributor

cspotcode commented Dec 15, 2020 via email

@Statfine
Copy link

@cspotcode which property can do it in my root tsconfig file or can you give an example

@cspotcode
Copy link
Contributor

https://github.com/TypeStrong/ts-node#options-via-tsconfigjson

{
  // a tsconfig file with ts-node options looks like this
  "compilerOptions": {
    // ... options here
  },
  "ts-node": {
    // ts-node options here
    "transpileOnly": true,
    "compiler": "ttypescript",
    // ts-node-specific overrides for compilerOptions
    // any compilerOptions specified here will override the values specified above, *only* when running in ts-node
    "compilerOptions": {
       
    }
}

@seyaobey
Copy link

I am facing the same problem. I've created a simple node + typescript. I'm having the same problem. I have tried to apply the solution from @cspotcode . Here is my tsconfig.json:

{
  "compilerOptions": {
    "module": "commonjs",
    "esModuleInterop": true,
    "target": "es6",
    "moduleResolution": "node",
    "sourceMap": true,
    "outDir": "dist"
  },
  "ts-node": {
    // ts-node options here
    "transpileOnly": true,
    "compiler": "ttypescript",
    // ts-node-specific overrides for compilerOptions
    // any compilerOptions specified here will override the values specified above, *only* when running in ts-node
    "compilerOptions": {
    }
  },
  "lib": ["es2015"]
}

Here is my package.json:

{
  "name": "nx-plop",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "plop": "plop --plotfile ./dist/plopfile.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "plop": "^2.7.4",
    "typescript": "^4.1.3"
  }
}

And this is my plopfile.js generated after build (npx tsc):

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = (plop) => {
    plop.setGenerator("file-gen", {
        description: 'My first generator',
        prompts: [],
        actions: []
    });
};
//# sourceMappingURL=plopfile.js.map

Please, could it be possible to have a simple example of the plop.js library setup with typescript?
Thank you for your work.

@FDiskas
Copy link
Contributor

FDiskas commented Jan 25, 2021

Plop uses ts-node so you are missing
"module": "CommonJS",

@ivanoats
Copy link

ivanoats commented Nov 1, 2021

Could we re-open this issue until a best practice approach to using typescript and plop is documented ?

@crutchcorn crutchcorn changed the title TypeScript example doesn't work Document tsconfig File for Plop Usage in TS Nov 2, 2021
@crutchcorn crutchcorn reopened this Nov 2, 2021
@crutchcorn
Copy link
Member

Fair enough @ivanoats. Changed the title. I'm working on some pretty major stabilization efforts for Plop currently (in prep for larger revamp efforts), but PRs are welcomed and will 100% be documented :)

@FDiskas maybe you wanna tackle this one?

If you update the README.md file, it'll auto update to the website when we deploy

@ivanoats
Copy link

ivanoats commented Nov 2, 2021

Awesome, thank you. I am happy to collaborate on a PR. I haven't figured it out myself but happy to test and document.

@crutchcorn
Copy link
Member

@ivanoats if you'd be willing to make a PR that'd be awesome

I've added an example usage of TS here:

https://github.com/plopjs/plop/blob/master/example/typescript/tsconfig.json

We require these values to be set for TSConfig and the TypeScript

We also may want to suggest users (despite not being required) use the import val = require('val') syntax, like it is here:

https://github.com/plopjs/plop/blob/master/example/typescript/plopfile.ts#L1-L2

This may silence other errors and verify/enforce that commonjs is set as the output.

@FDiskas
Copy link
Contributor

FDiskas commented Nov 3, 2021

@crutchcorn I created a small PR regarding this. Updated typescript example and added a note in the readme file. I'm a not native speaker so take a look at grammar also.
Also as artifact reformated the readme file as well.

@csantos-nydig
Copy link

csantos-nydig commented Jan 3, 2022

I'm running into this issue as well. I'm trying to apply some of the solutions mentioned on this PR, but unfortunately none works. (

What's the workaround to have plopfile.ts working?

Thanks

@FDiskas
Copy link
Contributor

FDiskas commented Jan 4, 2022

@csantos-nydig check the example #290

@danielfigueiredo
Copy link

danielfigueiredo commented Mar 15, 2022

I followed all instructions here and also what is in the example FDiskas linked but I keep getting the same error no matter what
Even if I run plop via ts-node which should be able to parse ts files I get this same error. My entire monorepo project only has TS packages and no JS at all, unfortunately, plop isn't there yet to work well with TS and even after tossing a few hours on it, I couldn't get it to work, so declaring bankruptcy on getting plopfile.ts to work.

[PLOP] Something went wrong with reading your plop file TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/dan/Projects/design-system/plopfile.ts
    at new NodeError (node:internal/errors:370:5)
    at Loader.defaultGetFormat [as _getFormat] (node:internal/modules/esm/get_format:71:15)
    at Loader.getFormat (node:internal/modules/esm/loader:105:42)
    at Loader.getModuleJob (node:internal/modules/esm/loader:243:31)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Loader.import (node:internal/modules/esm/loader:177:17)
    at async nodePlop (file:///Users/dan/Projects/design-system/node_modules/node-plop/src/node-plop.js:198:26)
    at async Liftoff.run (file:///Users/dan/Projects/design-system/node_modules/plop/src/plop.js:56:12) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}

☝️ this error keeps being thrown no matter what
I've added the "module": "commonjs" config to my tsconfig.json
Using latest plop version "plop": "^3.0.5",
and also using latest "ts-node": "^10.7.0",

🤷

Either way, I just wanted to say that this lib is great regardless so thanks for maintaining it

@cspotcode
Copy link
Contributor

@danielfigueiredo sounds like you've got "type": "module" in a package.json file?

Check out https://typestrong.org/ts-node/docs/module-type-overrides

@cspotcode
Copy link
Contributor

This error is mentioned in ts-node's docs, and I just made a small update to mention this specific situation: config files that you want to execute as CJS within an ESM project: https://typestrong.org/ts-node/docs/troubleshooting/#err_unknown_file_extension

Note that, if you really do need your config to run as ESM, then you're stuck using node's --loader which is gonna be a bit annoying, but that's node's fault; nothing we can do about it.

@danielfigueiredo
Copy link

Awesome! Thanks for the tips, I'll give that a try and will come back here later with the results. Is there a way we can specify a different tsconfig.json when running plop?
Apologies if I missed that, I've been mostly looking at https://plopjs.com/documentation/ as doc source

@cspotcode
Copy link
Contributor

You can probably specify a different tsconfig if you want, but first I would ask why you feel that you need to do that. Usually you actually don't need to specify a different tsconfig because any "ts-node": {} configuration added to your primary tsconfig is not going to conflict with anything else you're doing in your project.

@crutchcorn
Copy link
Member

This issue is really two things:

  1. Previously, we did not have an example of compiling a plopfile.js from TypeScript to MJS/CJS. This has now been done and even has tests backing up that it does indeed work with basic tsc && plop usage
  2. We want to support TypeScript OOTB without any additional configuration

Since # 1 is the main topic of discussion in this particular issue, I will be closing it in favor of #297 for # 2

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

Successfully merging a pull request may close this issue.