P4sca1 / cron-schedule

A zero-dependency cron parser and scheduler for Node.js, Deno and the browser.
MIT License
172 stars 14 forks source link

Build issue for scheduler import, with Vite #289

Closed ajmas closed 1 year ago

ajmas commented 1 year ago

The documentation indicates the following for the import for the scheduler:

import { IntervalBasedCronScheduler as scheduler } from 'cron-schedule/schedulers/interval-based.js'

Though when I do this in VS Code it says it cant' find it. The following works though, but then breaks in execution of the app:

import { IntervalBasedCronScheduler as scheduler } from 'cron-schedule/dist/schedulers/interval-based.js'

Originally I though this was a documentation issue, but now I am wondering whether the packaging has some issues, since if I use cron-schedule/schedulers/interval-based.js dev runtime works, build build time fails.

Error output:

src/views/MagicScreen.vue:45:54 - error TS2307: Cannot find module 'cron-schedule/schedulers/timer-based.js' or its corresponding type declarations.

45 import { TimerBasedCronScheduler as scheduler } from 'cron-schedule/schedulers/timer-based.js';
                                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

My import is presented as follows in my Vue file:

import { parseCronExpression } from 'cron-schedule';
import { TimerBasedCronScheduler as scheduler } from 'cron-schedule/schedulers/timer-based.js';

I am using Vite 3.2.3 for packaging.

Looking at issue #284, but yarn add cron-schedule@4.0.0-next.3 -S didn't change anything.

P4sca1 commented 1 year ago

Which version of cron-schedule, node, and typescript are you using?

ajmas commented 1 year ago

My last try was with 4.0.0-next.3, though I’ll double check to see what actually got installed.

ajmas commented 1 year ago

I have created a sample project which also shows the same issue:

https://github.com/ajmas/vue-cron-sample

The cron-schedue import is in src/components/HelloWorld.vue.

You can see the behaviour on npm run build.

Hopefully this helps you investigate.

ajmas commented 1 year ago

So investigation shows that Typescript doesn't deal with package exports too well.

What I ended up doing in a local checkout of cron-schedule is to export the schedulers via the default export:

import  { TimerBasedCronScheduler } from './schedulers/timer-based.js'
import  { IntervalBasedCronScheduler } from './schedulers/interval-based.js'

export * from './cron-parser.js'
export * from './cron.js'

export { TimerBasedCronScheduler, IntervalBasedCronScheduler }

With my Vite based Vue project, only the TimerBasedCronScheduler scheduler (the one I was using) ended up in the generated bundles, with IntervalBasedCronScheduler being excluded. This meant the change in approach didn't leave me with bundled unused dependencies.

P4sca1 commented 1 year ago

Have you tried "moduleResolution": "node16" in your tsconfig.json, and which version of typescript are you using?

ajmas commented 1 year ago

I tried a lot of things, include that. It creates other breakages.

BTW If anyone else sees this issue and can show by demonstration of a change to https://github.com/ajmas/vue-cron-sample makes this work, then I would be interested to know what you did.

Short term I am tempted to fork this project, and make the indicated changes, since I can't use it otherwise. Once Typescript finally addresses this then I can look to going back to the main fork. Right now this is a blocker in our project. We have already spent too may hours on this, so we are opting for the easy way out.

ajmas commented 1 year ago

I just saw that @intlify/unplugin-vue-i18n has a package export that works, suggesting the issue may be something to do with how things are packaged. I am able to import @intlify/unplugin-vue-i18n/vite. The export does look a little different:

  "./vite": {
      "require": "./lib/vite.cjs",
      "import": "./lib/vite.mjs",
      "types": "./vite.d.ts"
 }

I'll need to explore some more here, to see how it creates its distributables and then see if I can apply the same here?

Following the recipe here provided a working solution:

https://www.sensedeep.com/blog/posts/2021/how-to-create-single-source-npm-module.html

I'll create a PR for you to review.

ntsd commented 1 year ago

I got this problem also this pr will fix https://github.com/P4sca1/cron-schedule/pull/295

P4sca1 commented 1 year ago

If you’re using Node 12 or 14, you should use --moduleResolution node16. The features added to 16 have fully or mostly been backported to 12 and 14. --moduleResolution node is for Node 11 and older. Its name is currently bad. We plan to rename it accordingly.

https://github.com/microsoft/TypeScript/issues/50794

In order to use this package, you need to use moduleResolution node16 or nodenext.

aentwist commented 1 month ago

Hi - I have went through a fantastic journey to use this library. I straightened out my tsconfig, upgraded to TS 5, and switched to ESM (I must use in-browser). I will document it here in case it helps someone.

I would like to point out that the 2022 pull request for the linked issue directly contradicts the comment about tsconfig moduleResolution. package.json exports are supported by node16 [nodenext], and bundler, and Vite users should use bundler.

✅ Application authors who use a bundler on their TS or JS files before a runtime consumes that bundle [should use "moduleResolution": "bundler"]

It appears package exports have been available for TS since TS 4.7 using node16 or nodenext, and bundler was added in TS 5.

Important settings are also detailed. They have favorable defaults, don't worry about them.

  • resolvePackageJsonExports: Use the package.json 'exports' field when resolving package imports. Enabled by default in node16, nodenext, and bundler.
  • resolvePackageJsonImports: Use the package.json 'imports' field when resolving imports. Enabled by default in node16, nodenext, and bundler.

Finally, ESLint plugin import no-unresolved does not currently support package exports. The code base appears exclusive and the issue does not seem to have priority with the maintainers. To ignore resolution for libraries using package exports while still checking the ability to be located, we can use the rule's ignore setting.

"import/no-unresolved": ["error", { "ignore": "cron-schedule.*" }],