From 7eb0210d0551fb29de9c7a1aad6e4410ffc8ad0d Mon Sep 17 00:00:00 2001 From: Matthias Giger Date: Sun, 18 Feb 2024 14:49:54 +0100 Subject: [PATCH] feat(template): configure automatic React transform for TypeScript React no longer has to be imported. Also, adapt exports and make paths relative. Add react-typescript template. release-npm BREAKING CHANGE: React now uses automatic transform when using TypeScript. "exports" now prefixed with package namespace. --- README.md | 2 +- configuration/package.js | 28 ++++++++++++----- configuration/tsconfig.js | 2 +- package.json | 2 +- template/react-typescript/index.tsx | 3 ++ template/react-typescript/package.json | 14 +++++++++ template/react-typescript/template.json | 10 ++++++ template/react/index.jsx | 6 ++-- template/react/package.json | 8 ++--- test/configuration.test.js | 41 +++++++++++++++++-------- 10 files changed, 87 insertions(+), 29 deletions(-) create mode 100644 template/react-typescript/index.tsx create mode 100644 template/react-typescript/package.json create mode 100644 template/react-typescript/template.json diff --git a/README.md b/README.md index 15eb8ea..53c3d5a 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Alternatively, you can start with various templates: npm init now padua ./my-plugin [template] ``` -Replace `[template]` with one of the following available templates: default, node, react, typescript, test or cli. +Replace `[template]` with one of the following available templates: default, node, react, typescript, react-typescript, test or cli. ## Usage diff --git a/configuration/package.js b/configuration/package.js index 8bfcbae..34e7156 100644 --- a/configuration/package.js +++ b/configuration/package.js @@ -81,21 +81,23 @@ const switchable = (pkg) => { } if (options.typescript && !pkg.types) { - pkg.types = `${options.output}/index.d.ts` + pkg.types = `./${options.output}/index.d.ts` } else if (options.source && existsSync(join(getProjectBasePath(), 'index.d.ts'))) { - pkg.types = 'index.d.ts' + pkg.types = './index.d.ts' } else if (options.source && pkg.types && !existsSync(join(getProjectBasePath(), pkg.types))) { delete pkg.types } if (options.source) { if (pkg.main && !existsSync(join(getProjectBasePath(), pkg.main))) { - pkg.main = `${options.entry[0]}` + pkg.main = `./${options.entry[0]}` } if (!pkg.exports && !pkg.bin) { pkg.exports = { - default: `./${pkg.main}`, + '.': { + default: `./index.js`, + }, } } @@ -115,11 +117,23 @@ const switchable = (pkg) => { pkg.scripts.build = 'padua build' } if (!pkg.main) { - pkg.main = `${options.output}/index.js` + pkg.main = `./${options.output}/index.js` } if (!pkg.exports) { - pkg.exports = { - default: `./${pkg.main}`, + if (options.typescript) { + pkg.exports = { + '.': { + types: `./${options.output}/index.d.ts`, + // "default" condition must be last with most bundlers. + default: `./${options.output}/${pkg.main}`, + }, + } + } else { + pkg.exports = { + '.': { + default: `./${options.output}/${pkg.main}`, + }, + } } } } diff --git a/configuration/tsconfig.js b/configuration/tsconfig.js index 0892572..4f9bbb6 100644 --- a/configuration/tsconfig.js +++ b/configuration/tsconfig.js @@ -26,7 +26,7 @@ export const tsconfig = (tsconfigUserOverrides = {}) => { } if (options.react) { - packageTSConfig.compilerOptions.jsx = 'react' + packageTSConfig.compilerOptions.jsx = 'react-jsx' } userTSConfig = merge(userTSConfig, tsconfigUserOverrides) diff --git a/package.json b/package.json index 9bab6ec..82a0f6c 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "source": "index.js", "devDependencies": { "jest-fixture": "^4.1.0", - "vitest": "^1.2.2" + "vitest": "^1.3.0" }, "files": [ "configuration", diff --git a/template/react-typescript/index.tsx b/template/react-typescript/index.tsx new file mode 100644 index 0000000..81ee15b --- /dev/null +++ b/template/react-typescript/index.tsx @@ -0,0 +1,3 @@ +export default function App() { + return

Hello World

+} diff --git a/template/react-typescript/package.json b/template/react-typescript/package.json new file mode 100644 index 0000000..88fed60 --- /dev/null +++ b/template/react-typescript/package.json @@ -0,0 +1,14 @@ +{ + "name": "<%= name %>", + "description": "<%= description %>", + "version": "0.0.0", + "devDependencies": { + "@types/react": "^18.2.56", + "@types/react-dom": "^18.2.19", + "padua": "latest" + }, + "peerDependencies": { + "react": ">= 18", + "react-dom": ">= 18" + } +} diff --git a/template/react-typescript/template.json b/template/react-typescript/template.json new file mode 100644 index 0000000..b6f1b63 --- /dev/null +++ b/template/react-typescript/template.json @@ -0,0 +1,10 @@ +{ + "prompts": [ + { + "name": "name" + }, + { + "name": "description" + } + ] +} diff --git a/template/react/index.jsx b/template/react/index.jsx index 51887ee..81ee15b 100644 --- a/template/react/index.jsx +++ b/template/react/index.jsx @@ -1,3 +1,3 @@ -import React from 'react' - -export default () =>

Hello World

+export default function App() { + return

Hello World

+} diff --git a/template/react/package.json b/template/react/package.json index 4ec0c8e..e766a19 100644 --- a/template/react/package.json +++ b/template/react/package.json @@ -2,11 +2,11 @@ "name": "<%= name %>", "description": "<%= description %>", "version": "0.0.0", - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, "devDependencies": { "padua": "latest" + }, + "peerDependencies": { + "react": ">= 18", + "react-dom": ">= 18" } } diff --git a/test/configuration.test.js b/test/configuration.test.js index f4c6c5b..2185e70 100644 --- a/test/configuration.test.js +++ b/test/configuration.test.js @@ -33,7 +33,7 @@ test('Generates gitignore with default entries.', () => { const contents = readFile('.gitignore') expect(contents).toEqual( - ['node_modules', 'package-lock.json', 'jsconfig.json', 'dist', ''].join('\r\n') + ['node_modules', 'package-lock.json', 'jsconfig.json', 'dist', ''].join('\r\n'), ) }) @@ -45,7 +45,7 @@ test('Generates proper gitignore for typescript.', () => { const contents = readFile('.gitignore') expect(contents).toEqual( - ['node_modules', 'package-lock.json', 'tsconfig.json', 'dist', ''].join('\r\n') + ['node_modules', 'package-lock.json', 'tsconfig.json', 'dist', ''].join('\r\n'), ) }) @@ -181,6 +181,8 @@ test('Does not override configuration changes made by user after initial install expect(pkg.sideEffects).toBe(true) expect(pkg.scripts.start).toBe('my-own-script') expect(pkg.type).toBe(undefined) + expect(pkg.main).toBe('./dist/index.js') + expect(pkg.exports['.'].types).not.toBeDefined() }) test('eslintConfig extended when switching to source mode.', async () => { @@ -232,7 +234,7 @@ test('Type definitions will be added in source mode as soon as available.', asyn pkg = readFile('package.json') - expect(pkg.types).toBe('index.d.ts') + expect(pkg.types).toBe('./index.d.ts') unlinkSync(join(process.cwd(), 'index.d.ts')) @@ -270,6 +272,21 @@ test('Source entry will not be added again if removed by user.', async () => { expect(pkg.source).not.toBeDefined() }) +test('Types will be added.', async () => { + prepare([packageJson('typescript'), file('index.tsx', '')]) + + await writePackageJson() + + const pkg = readFile('package.json') + + expect(pkg.jest).not.toBeDefined() + // "default" must be last. + expect(Object.keys(pkg.exports['.'])[0]).toBe('types') + expect(pkg.main).toBe('./dist/index.js') + expect(pkg.types).toBe('./dist/index.d.ts') + expect(pkg.files).toEqual(['dist']) +}) + test('Files array is only changed initially.', async () => { prepare([ packageJson('source', { @@ -431,15 +448,15 @@ test('Ignores are written to all configuration files.', async () => { file('test/basic.test.js', ''), file( 'node_modules/padua/configuration/.prettierignore', - readFile('../../../configuration/.prettierignore') + readFile('../../../configuration/.prettierignore'), ), file( 'node_modules/padua/configuration/eslint.cjs', - readFile('../../../configuration/eslint.cjs') + readFile('../../../configuration/eslint.cjs'), ), file( 'node_modules/padua/configuration/stylelint.cjs', - readFile('../../../configuration/stylelint.cjs') + readFile('../../../configuration/stylelint.cjs'), ), ]) @@ -533,15 +550,15 @@ test('Proper ignores added when values are empty.', async () => { file('test/basic.test.js', ''), file( 'node_modules/padua/configuration/.prettierignore', - readFile('../../../configuration/.prettierignore') + readFile('../../../configuration/.prettierignore'), ), file( 'node_modules/padua/configuration/eslint.cjs', - readFile('../../../configuration/eslint.cjs') + readFile('../../../configuration/eslint.cjs'), ), file( 'node_modules/padua/configuration/stylelint.cjs', - readFile('../../../configuration/stylelint.cjs') + readFile('../../../configuration/stylelint.cjs'), ), ]) @@ -587,15 +604,15 @@ test('Ignores work with all possible configurations.', async () => { file('test/basic.test.js', ''), file( 'node_modules/padua/configuration/.prettierignore', - readFile('../../../configuration/.prettierignore') + readFile('../../../configuration/.prettierignore'), ), file( 'node_modules/padua/configuration/eslint.cjs', - readFile('../../../configuration/eslint.cjs') + readFile('../../../configuration/eslint.cjs'), ), file( 'node_modules/padua/configuration/stylelint.cjs', - readFile('../../../configuration/stylelint.cjs') + readFile('../../../configuration/stylelint.cjs'), ), ])