You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Nov 7, 2023. It is now read-only.
Temir is a very cool package but has some rough edges. I just want to briefly go over some of the issues I have run into, some of the solutions, and remaining issues. Hopefully you can walk away with a better idea as to whether this library fits your use-case.
I think many of the Pros speak for themselves, this is one of the few (maybe only?) reactive cli tools with automatic dep tracking (courtesy of Vue). I had no issues with the reactivity, that all functions just as you'd expect.
Issues:
Small Community, Few Refences, Mostly Unmaintained:
There is no discussion tab on this repo, no discord, and issues seem to be unaddressed.
If you are having trouble, the best I can do is point you to these few references and maybe you can compare your work or strip their repos and use them as a template.
Undocumented Features:
If you plan to use this repo, it may be beneficial to review Ink's docs as this repo is based on it. It will also be beneficial to look over the Temir's source code. In both cases you'll find things that exist here but are undocumented, like waitUntilExit() and other render/instance methods.
TS Dependency Issues Preventing Build:
The functionality of this repo's examples are currently dependent upon the lock file. If you delete that and rebuild, you will run into issues. Likewise, if you are starting a project from scratch without knowing this, you will likely run into these issues as well. One option is to just not use TS I suppose...
Others have clearly gotten TS to work, so let them be your guide:
Or wait for the maintainer to addresses this issue.
(I'll mention another solution later - tips: building below)
Select input broken
I mainly just wanted to use this repo for a convenient "item selection list", but was disappointed to find it was broken.
If you arrow down then back up, things break. I stripped the original and rolled my own here. Hopefully someone may find it of use or otherwise find the bug in the original.
Double console.log
I was able to avoid it, most probably can as well. It is a little annoying tho.
Depending ones use case, render(app, { patchConsole: false }) may help.
No Text Input Component
If this is something you require, you will have to roll your own. You may wish to use this ink version as a reference. Or, maybe leverage more vanilla libs like Inquirer.
Tips:
App vs Commands
Going into you're project, you should have an idea as to whether you want CLI tool to be an App or Command based.
I don't have, much to say about making a pure app but you can reference this snake game if you need help.
For command-based tools, you will want to use the render function more synchronously as well as pass data:
functionender(renderer){renderer.clear()renderer.unmount()}letrenderWait=async(component,cb)=>{letr,argsTmp;letresolvableCB=(...args)=>{argsTmp=args;ender(r)}r=render(component(resolvableCB))awaitr.waitUntilExit()// wait for resolvableCB() to execute ender()// We forward args to avoid race condition and double console.logif(!Array.isArray(argsTmp))process.exit(1)// quit without selectingreturnawaitcb(...argsTmp)}program.command('someCommand').action(async(options,cmd)=>{letoutPut=awaitrenderWait(cb=><Selectoritems={items}onSubmit={cb}/>,selected=>{console.log('Selected:',selected.value)returnselected.value})})// this could probably be betterletrenderPromise=async(component,cb)=>{returnnewPromise(async(resolve,reject)=>{letr;letresolvableCB=(...args)=>{ender(r);// exit first to prevent double log issueresolve(cb(...args))}r=render(component(resolvableCB))})}program.command('someCommand').action(async(options,cmd)=>{letoutPut=awaitrenderPromise(cb=><Selectoritems={items}onSubmit={cb}/>,selected=>{console.log('Selected:',selected.value)returnselected.value})})
Building:
Because I ran into TS issues with the unbuild version and also prefer to have a transparent build process, I chose Vite to build:
import{defineConfig}from'vite';importvuefrom'@vitejs/plugin-vue'importvueJsxfrom'@vitejs/plugin-vue-jsx'import{dependencies}from'./package.json'// Node modules will have to be registered manually hereletnode_libs=['util','os','child_process','stream','path','fs'// can prob replace with `import { builtinModules } from "module"`].flatMap(m=>[m,`node:${m}`])letpkg_deps=Object.keys(dependencies)letpkg_dep_map=Object.fromEntries(pkg_deps.map(m=>[m,m.replaceAll(/[\@\/\:]/g,'_')]))exportdefaultdefineConfig({plugins: [vue(),vueJsx(),shebang('./dist/index.js'),del('./dist/index.umd.cjs')],build: {minify: false,lib: {entry: './index.jsx',fileName: 'index',name: 'default',},rollupOptions: {external: [ ...pkg_deps, ...node_libs],output: {globals: {
...pkg_dep_map,
...Object.fromEntries(node_libs.map(m=>[m,m]))}}}}})importfsfrom'fs'functionshebang(pathToBang){return{name: 'remove-main-script',enforce: 'post',apply: 'build',closeBundle: async()=>{if(!fs.existsSync(pathToBang))returnletstringToPrepend=`#! /usr/bin/env node\n\n`try{constdata=fs.readFileSync(pathToBang,'utf8')fs.writeFileSync(pathToBang,stringToPrepend+data)}catch(err){console.error(err);}}}}functiondel(pathToRm){return{name: 'del',enforce: 'post',apply: 'build',closeBundle: async()=>{if(!fs.existsSync(pathToRm))returnfs.rmSync(pathToRm,{recursive: true})}}}
I am no Vite expert, so there are probably improvements to be made.
Don't pass entry script to args
If you are taking a command-based approach, you will only want to pass the given args to the program.
This is a problem with the temir cli, where the given file to be served is passed as an arg...
{
"scripts": {
"start": "temir entryFile.jsx"
}
}
To alleviate this, you may want to create a serve file that hardcodes the entry point:
// serve.js// Allows us to start the dev server without passing index as an cmd-line arg import{runDevServer}from'@temir/cli'runDevServer('./entryFile.jsx')
node serve.js
NOTE: runDevServer() defaults to 'src/main.ts' rather than checking your entry in package.json...
HMR
Again, when dealing with a command-based approach, there are times when HMR gets in the way.
An example might be starting a server on a given port or something that doesn't use the renderer at all:
You'll probably want to use process.exit() for renderless commands.
For things like a server, it would be nice to use something similar to import.meta?.hot.on('vite:beforeUpdate', ()=>{}) to clean up long running/persistent processes. However, I haven't found a similar function in vite-node as of yet...
Closing Statement:
I love how powerful and versatile Vue is and preferer to use it when possible. Despite the issues I ran into, I believe there is still great potential for this repo. However, in its current state I would not use it for something I need done quickly or professionally. Hopefully others may share their tips and trick to build up more of a community around this tool, I would love for it to become an obvious choice over Ink someday.
The text was updated successfully, but these errors were encountered:
I almost wonder if building components in mitosis might appeal to a larger audience, then people can take them back to their framework specific renderers ( assuming they all use an Ink based api ).
Hi @tcardlab. Thank you for your suggestions and such detailed feedback. We plan to migrate temir to vue-termui. (I‘ll address this point in the README.) For several reasons, our work at vue-termui is currently not able to provide very active maintenance. If you're interested in it, we'd love to have you contribute and join us. Thanks again for enjoying it and providing such detailed feedback. ♥️
Sign up for freeto subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Temir is a very cool package but has some rough edges. I just want to briefly go over some of the issues I have run into, some of the solutions, and remaining issues. Hopefully you can walk away with a better idea as to whether this library fits your use-case.
I think many of the Pros speak for themselves, this is one of the few (maybe only?) reactive cli tools with automatic dep tracking (courtesy of Vue). I had no issues with the reactivity, that all functions just as you'd expect.
Issues:
Small Community, Few Refences, Mostly Unmaintained:
There is no discussion tab on this repo, no discord, and issues seem to be unaddressed.
If you are having trouble, the best I can do is point you to these few references and maybe you can compare your work or strip their repos and use them as a template.
Undocumented Features:
If you plan to use this repo, it may be beneficial to review Ink's docs as this repo is based on it. It will also be beneficial to look over the Temir's source code. In both cases you'll find things that exist here but are undocumented, like
waitUntilExit()
and other render/instance methods.TS Dependency Issues Preventing Build:
The functionality of this repo's examples are currently dependent upon the lock file. If you delete that and rebuild, you will run into issues. Likewise, if you are starting a project from scratch without knowing this, you will likely run into these issues as well. One option is to just not use TS I suppose...
Others have clearly gotten TS to work, so let them be your guide:
Or wait for the maintainer to addresses this issue.
(I'll mention another solution later -
tips: building
below)Select input broken
I mainly just wanted to use this repo for a convenient "item selection list", but was disappointed to find it was broken.
If you arrow down then back up, things break. I stripped the original and rolled my own here. Hopefully someone may find it of use or otherwise find the bug in the original.
Double console.log
I was able to avoid it, most probably can as well. It is a little annoying tho.
Depending ones use case,
render(app, { patchConsole: false })
may help.No Text Input Component
If this is something you require, you will have to roll your own. You may wish to use this ink version as a reference. Or, maybe leverage more vanilla libs like Inquirer.
Tips:
App vs Commands
Going into you're project, you should have an idea as to whether you want CLI tool to be an App or Command based.
I don't have, much to say about making a pure app but you can reference this snake game if you need help.
For command-based tools, you will want to use the render function more synchronously as well as pass data:
Building:
Because I ran into TS issues with the unbuild version and also prefer to have a transparent build process, I chose Vite to build:
I am no Vite expert, so there are probably improvements to be made.
Don't pass entry script to args
If you are taking a command-based approach, you will only want to pass the given args to the program.
This is a problem with the temir cli, where the given file to be served is passed as an arg...
To alleviate this, you may want to create a serve file that hardcodes the entry point:
node serve.js
HMR
Again, when dealing with a command-based approach, there are times when HMR gets in the way.
An example might be starting a server on a given port or something that doesn't use the renderer at all:
process.exit()
for renderless commands.import.meta?.hot.on('vite:beforeUpdate', ()=>{})
to clean up long running/persistent processes. However, I haven't found a similar function invite-node
as of yet...Closing Statement:
I love how powerful and versatile Vue is and preferer to use it when possible. Despite the issues I ran into, I believe there is still great potential for this repo. However, in its current state I would not use it for something I need done quickly or professionally. Hopefully others may share their tips and trick to build up more of a community around this tool, I would love for it to become an obvious choice over Ink someday.
The text was updated successfully, but these errors were encountered: