imjuni / ctix

CLI to generate barrel file for webpack, rollup entrypoint
MIT License
81 stars 21 forks source link

NextJS use client directive feature & duplicate FirstLineComment fix #71

Closed jookshub closed 1 year ago

jookshub commented 1 year ago

Hi! 👋

Firstly, thanks for your work on this project! 🙂

Today I used patch-package to patch ctix@1.6.0 for the project I'm working on.

In order to circumvent this issue with NextJS https://github.com/vercel/next.js/issues/41940 I had to include the 'use client' directive into multiple index files, so I've leveraged your project to do that via CLI.

Along the way I've also fixed the duplicated output of comment/timestamp in the indexFileWrite function. The firstLine is included in prettierApplied so there is no need to redo that when prettierApplied gets used.

I did not check against other configurations and consider this a quick working draft that helps me moving forward to other more pressing issues 🙂 I might be able to improve this solution at another time.

Here is the diff that solved my problem:

diff --git a/node_modules/ctix/dist/cli.js b/node_modules/ctix/dist/cli.js
index 85f381f..7c255e2 100755
--- a/node_modules/ctix/dist/cli.js
+++ b/node_modules/ctix/dist/cli.js
@@ -152,6 +152,12 @@ function createSingleBuilder(args) {
         describe: 'add ctix comment at first line of creted index.ts file, that remark created from ctix',
         type: 'boolean',
         default: false,
+    })
+        .option('useNextJsClientDirective', {
+        alias: 'd',
+        describe: 'add \'use client\' directive as first line into created index.ts files',
+        type: 'boolean',
+        default: false,
     })
         .option('quote', {
         alias: 'q',
@@ -219,6 +225,11 @@ function initBuilder(args) {
         describe: 'add ctix comment at first line of creted index.ts file, that remark created from ctix',
         type: 'boolean',
         default: false,
+    })
+        .option('useNextJsClientDirective', {
+        describe: 'add \'use client\' directive as first line into created index.ts files',
+        type: 'boolean',
+        default: false,
     })
         .option('quote', {
         describe: 'change quote character at export syntax',
@@ -1091,6 +1102,9 @@ const initialConfigLiteral = `{
   // add ctix comment at first line of creted index.ts file, that remark created from ctix
   "useComment": false,

+  // add 'use client' directive as first line into created index.ts files
+  "useNextJsClientDirective": false,
+
   // quote mark " or '
   "quote": "'",
   // overwrite index.ts file also index.ts file already exist that create backup file
@@ -1958,14 +1972,15 @@ async function prettierApply(project, contents) {

 function getFirstLineComment(option) {
     const today = dayjs__default["default"]();
+    const useClient = option.useNextJsClientDirective ? `'use client';\n\r` : '';
     if (option.useComment && option.useTimestamp) {
-        return `// created from ctix ${today.format('YYYY-MM-DD HH:mm:ss')}${option.eol}${option.eol}`;
+        return `${useClient}// created from ctix ${today.format('YYYY-MM-DD HH:mm:ss')}${option.eol}${option.eol}`;
     }
     if (option.useComment) {
-        return `// created from ctix${option.eol}${option.eol}`;
+        return `${useClient}// created from ctix${option.eol}${option.eol}`;
     }
     if (option.useTimestamp) {
-        return `// ${today.format('YYYY-MM-DD HH:mm:ss')}${option.eol}${option.eol}`;
+        return `${useClient}// ${today.format('YYYY-MM-DD HH:mm:ss')}${option.eol}${option.eol}`;
     }
     return '';
 }
@@ -1979,11 +1994,11 @@ async function indexFileWrite(indexInfos, option) {
             if ((await myNodeFp.exists(indexFilePath)) && option.noBackup === false) {
                 await fs__default["default"].promises.writeFile(`${indexFilePath}.bak`, await fs__default["default"].promises.readFile(indexFilePath));
             }
-            await fs__default["default"].promises.writeFile(indexFilePath, `${`${firstLine}${prettierApplied.contents}`.trim()}${option.eol}`);
+            await fs__default["default"].promises.writeFile(indexFilePath, `${`${prettierApplied.contents}`.trim()}${option.eol}`);
             return undefined;
         }
         if ((await myNodeFp.exists(indexFilePath)) === false) {
-            await fs__default["default"].promises.writeFile(indexFilePath, `${`${firstLine}${prettierApplied.contents}`.trim()}${option.eol}`);
+            await fs__default["default"].promises.writeFile(indexFilePath, `${`${prettierApplied.contents}`.trim()}${option.eol}`);
             return undefined;
         }
         const reason = {
@@ -2160,6 +2175,9 @@ async function createInitFile(option, isMessageDisplay) {
         if (option.useComment != null) {
             modifiedInitialConfig = jsoncParser.applyEdits(modifiedInitialConfig, jsoncParser.modify(modifiedInitialConfig, ['useComment'], option.useComment, options));
         }
+        if (option.useNextJsClientDirective != null) {
+          modifiedInitialConfig = jsoncParser.applyEdits(modifiedInitialConfig, jsoncParser.modify(modifiedInitialConfig, ['useNextJsClientDirective'], option.useNextJsClientDirective, options));
+        }
         if (option.quote != null) {
             modifiedInitialConfig = jsoncParser.applyEdits(modifiedInitialConfig, jsoncParser.modify(modifiedInitialConfig, ['quote'], option.quote, options));
         }

This issue body was partially generated by patch-package.

imjuni commented 1 year ago

Hi @jookshub , Thank you for your feedback!

I think that change like below,

.option('useDirective', {
    describe: 'add directive as first line into created index.ts files. eg. \'use client\' ',
    type: 'string',
})

I think that useDirective option is useful for many people as well as next.js user

imjuni commented 1 year ago

Hi @jookshub,

I add useDirective option in v1.8.0, You can use this option like that,

ctix single -p tsconfig.json -useDirective "'use client'"