From 3de26f4c2014bc38e34854b0bfc9b535fc2dd687 Mon Sep 17 00:00:00 2001 From: Jared Henderson Date: Thu, 18 Nov 2021 09:13:18 -0500 Subject: [PATCH 1/6] support commonjs as well as ESM consumption --- .npmignore | 4 +++- package.json | 6 ++++-- tsconfig.cjs.json | 8 ++++++++ tsconfig.json | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 tsconfig.cjs.json diff --git a/.npmignore b/.npmignore index f586bd6..f428f92 100644 --- a/.npmignore +++ b/.npmignore @@ -1,7 +1,9 @@ .DS_Store node_modules/ -jest.config.js +jest.config.json +src/ *.swp *.md tsconfig.json +tsconfig.cjs.json babel.config.js diff --git a/package.json b/package.json index 57b2475..b6d174f 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,9 @@ "version": "2.0.7", "description": "simple, expressive API for tailwindcss + react-native", "author": "Jared Henderson ", - "main": "dist/index.js", + "module": "dist/esm/index.js", + "types": "dist/esm/index.d.ts", + "main": "dist/cjs/index.js", "license": "MIT", "scripts": { "test": "jest", @@ -14,7 +16,7 @@ "ts:check": "fldev ts:check", "format": "fldev format", "format:check": "fldev format --check", - "compile": "fldev ts:compile", + "compile": "fldev ts:compile && fldev ts:compile --project tsconfig.cjs.json", "prepublishOnly": "npm run compile", "npub:precheck": "npm run lint && npm run format:check && npm run ts:check && npm run test" }, diff --git a/tsconfig.cjs.json b/tsconfig.cjs.json new file mode 100644 index 0000000..3b34abb --- /dev/null +++ b/tsconfig.cjs.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "CommonJS", + "outDir": "./dist/cjs", + "declaration": false + } +} diff --git a/tsconfig.json b/tsconfig.json index 071ea2c..446582b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,7 +6,7 @@ "noImplicitOverride": true, "skipLibCheck": true, "rootDir": "./src", - "outDir": "./dist", + "outDir": "./dist/esm", "lib": ["ES2019"], "target": "ES2019", "declaration": true, From 2d2b27dfb2fdd35d113211a6b94ed6654f7a39cd Mon Sep 17 00:00:00 2001 From: Fabian Finke Date: Thu, 18 Nov 2021 16:11:18 +0100 Subject: [PATCH 2/6] refactor: remove react-native dependency from create function --- src/ClassParser.ts | 6 +- src/__tests__/prefix-match.spec.ts | 4 +- src/create.ts | 221 +++++++++++++++++++++++++++++ src/index.ts | 219 ++-------------------------- 4 files changed, 238 insertions(+), 212 deletions(-) create mode 100644 src/create.ts diff --git a/src/ClassParser.ts b/src/ClassParser.ts index 9a8b8b8..ed8a3ae 100644 --- a/src/ClassParser.ts +++ b/src/ClassParser.ts @@ -1,10 +1,9 @@ -import { Platform as RnPlatform } from 'react-native'; import fontSize from './resolve/font-size'; import lineHeight from './resolve/line-height'; import spacing from './resolve/spacing'; import screens from './screens'; import { TwConfig } from './tw-config'; -import { StyleIR, isOrientation, isPlatform, DeviceContext, ParseContext } from './types'; +import { StyleIR, isOrientation, isPlatform, DeviceContext, ParseContext, Platform } from './types'; import fontFamily from './resolve/font-family'; import { color, colorOpacity } from './resolve/color'; import { border, borderRadius } from './resolve/borders'; @@ -38,6 +37,7 @@ export default class ClassParser { private config: TwConfig = {}, private cache: Cache, device: DeviceContext, + platform: Platform ) { this.context.device = device; const parts = input.trim().split(`:`); @@ -70,7 +70,7 @@ export default class ClassParser { this.isNull = true; } } else if (isPlatform(prefix)) { - this.isNull = prefix !== RnPlatform.OS; + this.isNull = prefix !== platform; } else if (isOrientation(prefix)) { if (!device.windowDimensions) { this.isNull = true; diff --git a/src/__tests__/prefix-match.spec.ts b/src/__tests__/prefix-match.spec.ts index 91156a0..6199045 100644 --- a/src/__tests__/prefix-match.spec.ts +++ b/src/__tests__/prefix-match.spec.ts @@ -18,10 +18,11 @@ describe(`tw.prefixMatch()`, () => { test(`platform prefixes`, () => { rn.Platform.OS = `ios`; + tw = create(); expect(tw.prefixMatch(`ios`)).toBe(true); expect(tw.prefixMatch(`android`)).toBe(false); - tw = create(); rn.Platform.OS = `android`; + tw = create(); expect(tw.prefixMatch(`ios`)).toBe(false); expect(tw.prefixMatch(`android`)).toBe(true); }); @@ -46,6 +47,7 @@ describe(`tw.prefixMatch()`, () => { test(`multiple prefixes`, () => { rn.Platform.OS = `ios`; + tw = create(); tw.setWindowDimensions({ width: 800, height: 600 }); expect(tw.prefixMatch(`min-w-[500px]`, `max-w-[600px]`)).toBe(false); expect(tw.prefixMatch(`min-w-[500px]`, `max-w-[900px]`)).toBe(true); diff --git a/src/create.ts b/src/create.ts new file mode 100644 index 0000000..6dfbf68 --- /dev/null +++ b/src/create.ts @@ -0,0 +1,221 @@ +import resolveConfig from "tailwindcss/resolveConfig"; +import { + ClassInput, + DependentStyle, + Style, + TailwindFn, + RnColorScheme, + OrderedStyle, + StyleIR, + DeviceContext, + Platform, +} from "./types"; +import { TwConfig } from "./tw-config"; +import Cache from "./cache"; +import ClassParser from "./ClassParser"; +import { parseInputs } from "./parse-inputs"; +import { complete, warn } from "./helpers"; +import { getAddedUtilities } from "./plugin"; +import { removeOpacityHelpers } from "./resolve/color"; + +export function create(customConfig: TwConfig, platform: Platform): TailwindFn { + const config = resolveConfig(customConfig as any) as TwConfig; + const device: DeviceContext = {}; + + const pluginUtils = getAddedUtilities(config.plugins); + const customStringUtils: Record = {}; + const customStyleUtils = Object.entries(pluginUtils) + .map(([util, style]): [string, StyleIR] => { + if (typeof style === `string`) { + // mutating while mapping, i know - bad form, but for performance sake... ¯\_(ツ)_/¯ + customStringUtils[util] = style; + return [util, { kind: `null` }]; + } + return [util, complete(style)]; + }) + .filter(([, ir]) => ir.kind !== `null`); + + function deriveCacheGroup(): string { + return ( + [ + device.windowDimensions ? `w${device.windowDimensions.width}` : false, + device.windowDimensions ? `h${device.windowDimensions.height}` : false, + device.fontScale ? `fs${device.fontScale}` : false, + device.colorScheme === `dark` ? `dark` : false, + device.pixelDensity === 2 ? `retina` : false, + ] + .filter(Boolean) + .join(`--`) || `default` + ); + } + + let cacheGroup = deriveCacheGroup(); + const contextCaches: Record = {}; + + function getCache(): Cache { + const existing = contextCaches[cacheGroup]; + if (existing) { + return existing; + } + const cache = new Cache(customStyleUtils); + contextCaches[cacheGroup] = cache; + return cache; + } + + function style(...inputs: ClassInput[]): Style { + const cache = getCache(); + let resolved: Style = {}; + const dependents: DependentStyle[] = []; + const ordered: OrderedStyle[] = []; + const [utilities, userStyle] = parseInputs(inputs); + + // check if we've seen this full set of classes before + // if we have a cached copy, we can skip examining each utility + const joined = utilities.join(` `); + const cached = cache.getStyle(joined); + if (cached) { + return { ...cached, ...(userStyle ? userStyle : {}) }; + } + + for (const utility of utilities) { + let styleIr = cache.getIr(utility); + + if (!styleIr && utility in customStringUtils) { + const customStyle = style(customStringUtils[utility]); + cache.setIr(utility, complete(customStyle)); + resolved = { ...resolved, ...customStyle }; + continue; + } + + const parser = new ClassParser(utility, config, cache, device, platform); + styleIr = parser.parse(); + + switch (styleIr.kind) { + case `complete`: + resolved = { ...resolved, ...styleIr.style }; + cache.setIr(utility, styleIr); + break; + case `dependent`: + dependents.push(styleIr); + break; + case `ordered`: + ordered.push(styleIr); + break; + case `null`: + cache.setIr(utility, styleIr); + break; + } + } + + if (ordered.length > 0) { + ordered.sort((a, b) => a.order - b.order); + for (const orderedStyle of ordered) { + switch (orderedStyle.styleIr.kind) { + case `complete`: + resolved = { ...resolved, ...orderedStyle.styleIr.style }; + break; + case `dependent`: + dependents.push(orderedStyle.styleIr); + break; + } + } + } + + if (dependents.length > 0) { + for (const dependent of dependents) { + const error = dependent.complete(resolved); + if (error) { + warn(error); + } + } + removeOpacityHelpers(resolved); + } + + // cache the full set of classes for future re-renders + // it's important we cache BEFORE merging in userStyle below + if (joined !== ``) { + cache.setStyle(joined, resolved); + } + + if (userStyle) { + resolved = { ...resolved, ...userStyle }; + } + + return resolved; + } + + function color(utils: string): string | undefined { + const styleObj = style( + utils + .split(/\s+/g) + .map((util) => util.replace(/^(bg|text)-/, ``)) + .map((util) => `bg-${util}`) + .join(` `) + ); + return typeof styleObj.backgroundColor === `string` + ? styleObj.backgroundColor + : undefined; + } + + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + const tailwindFn = ( + strings: TemplateStringsArray, + ...values: (string | number)[] + ) => { + let str = ``; + strings.forEach((string, i) => { + str += string + (values[i] || ``); + }); + return style(str); + }; + + tailwindFn.style = style; + tailwindFn.color = color; + + tailwindFn.prefixMatch = (...prefixes: string[]) => { + const joined = prefixes.sort().join(`:`); + const cache = getCache(); + const cached = cache.getPrefixMatch(joined); + if (cached !== undefined) { + return cached; + } + const parser = new ClassParser( + `${joined}:flex`, + config, + cache, + device, + platform + ); + const ir = parser.parse(); + const prefixMatches = ir.kind !== `null`; + cache.setPrefixMatch(joined, prefixMatches); + return prefixMatches; + }; + + tailwindFn.setWindowDimensions = (newDimensions: { + width: number; + height: number; + }) => { + device.windowDimensions = newDimensions; + cacheGroup = deriveCacheGroup(); + }; + + tailwindFn.setFontScale = (newFontScale: number) => { + device.fontScale = newFontScale; + cacheGroup = deriveCacheGroup(); + }; + + tailwindFn.setPixelDensity = (newPixelDensity: 1 | 2) => { + device.pixelDensity = newPixelDensity; + cacheGroup = deriveCacheGroup(); + }; + + tailwindFn.setColorScheme = (newColorScheme: RnColorScheme) => { + device.colorScheme = newColorScheme; + cacheGroup = deriveCacheGroup(); + }; + + return tailwindFn; +} + +export default create; diff --git a/src/index.ts b/src/index.ts index 6b4bdea..267e4eb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,213 +1,16 @@ -import resolveConfig from 'tailwindcss/resolveConfig'; -import { - ClassInput, - DependentStyle, - Style, - TailwindFn, - RnColorScheme, - OrderedStyle, - StyleIR, - DeviceContext, -} from './types'; -import { TwConfig } from './tw-config'; -import Cache from './cache'; -import ClassParser from './ClassParser'; -import { parseInputs } from './parse-inputs'; -import { complete, warn } from './helpers'; -import plugin, { getAddedUtilities } from './plugin'; -import { removeOpacityHelpers } from './resolve/color'; +import { Platform } from "react-native"; +import { TailwindFn } from "./types"; +import { TwConfig } from "./tw-config"; +import plugin from "./plugin"; +import rawCreate from "./create"; -export { plugin }; -export type { TailwindFn, TwConfig }; -export { useDeviceContext } from './hooks'; - -export function create(customConfig: TwConfig = {}): TailwindFn { - const config = resolveConfig(customConfig as any) as TwConfig; - const device: DeviceContext = {}; - - const pluginUtils = getAddedUtilities(config.plugins); - const customStringUtils: Record = {}; - const customStyleUtils = Object.entries(pluginUtils) - .map(([util, style]): [string, StyleIR] => { - if (typeof style === `string`) { - // mutating while mapping, i know - bad form, but for performance sake... ¯\_(ツ)_/¯ - customStringUtils[util] = style; - return [util, { kind: `null` }]; - } - return [util, complete(style)]; - }) - .filter(([, ir]) => ir.kind !== `null`); - - function deriveCacheGroup(): string { - return ( - [ - device.windowDimensions ? `w${device.windowDimensions.width}` : false, - device.windowDimensions ? `h${device.windowDimensions.height}` : false, - device.fontScale ? `fs${device.fontScale}` : false, - device.colorScheme === `dark` ? `dark` : false, - device.pixelDensity === 2 ? `retina` : false, - ] - .filter(Boolean) - .join(`--`) || `default` - ); - } - - let cacheGroup = deriveCacheGroup(); - const contextCaches: Record = {}; - - function getCache(): Cache { - const existing = contextCaches[cacheGroup]; - if (existing) { - return existing; - } - const cache = new Cache(customStyleUtils); - contextCaches[cacheGroup] = cache; - return cache; - } - - function style(...inputs: ClassInput[]): Style { - const cache = getCache(); - let resolved: Style = {}; - const dependents: DependentStyle[] = []; - const ordered: OrderedStyle[] = []; - const [utilities, userStyle] = parseInputs(inputs); - - // check if we've seen this full set of classes before - // if we have a cached copy, we can skip examining each utility - const joined = utilities.join(` `); - const cached = cache.getStyle(joined); - if (cached) { - return { ...cached, ...(userStyle ? userStyle : {}) }; - } - - for (const utility of utilities) { - let styleIr = cache.getIr(utility); - - if (!styleIr && utility in customStringUtils) { - const customStyle = style(customStringUtils[utility]); - cache.setIr(utility, complete(customStyle)); - resolved = { ...resolved, ...customStyle }; - continue; - } - - const parser = new ClassParser(utility, config, cache, device); - styleIr = parser.parse(); - - switch (styleIr.kind) { - case `complete`: - resolved = { ...resolved, ...styleIr.style }; - cache.setIr(utility, styleIr); - break; - case `dependent`: - dependents.push(styleIr); - break; - case `ordered`: - ordered.push(styleIr); - break; - case `null`: - cache.setIr(utility, styleIr); - break; - } - } - - if (ordered.length > 0) { - ordered.sort((a, b) => a.order - b.order); - for (const orderedStyle of ordered) { - switch (orderedStyle.styleIr.kind) { - case `complete`: - resolved = { ...resolved, ...orderedStyle.styleIr.style }; - break; - case `dependent`: - dependents.push(orderedStyle.styleIr); - break; - } - } - } +// Apply default config and inject RN Platform +const create = (twConfig: TwConfig = {}): TailwindFn => + rawCreate(twConfig, Platform.OS); - if (dependents.length > 0) { - for (const dependent of dependents) { - const error = dependent.complete(resolved); - if (error) { - warn(error); - } - } - removeOpacityHelpers(resolved); - } - - // cache the full set of classes for future re-renders - // it's important we cache BEFORE merging in userStyle below - if (joined !== ``) { - cache.setStyle(joined, resolved); - } - - if (userStyle) { - resolved = { ...resolved, ...userStyle }; - } - - return resolved; - } - - function color(utils: string): string | undefined { - const styleObj = style( - utils - .split(/\s+/g) - .map((util) => util.replace(/^(bg|text)-/, ``)) - .map((util) => `bg-${util}`) - .join(` `), - ); - return typeof styleObj.backgroundColor === `string` - ? styleObj.backgroundColor - : undefined; - } - - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - const tailwindFn = (strings: TemplateStringsArray, ...values: (string | number)[]) => { - let str = ``; - strings.forEach((string, i) => { - str += string + (values[i] || ``); - }); - return style(str); - }; - - tailwindFn.style = style; - tailwindFn.color = color; - - tailwindFn.prefixMatch = (...prefixes: string[]) => { - const joined = prefixes.sort().join(`:`); - const cache = getCache(); - const cached = cache.getPrefixMatch(joined); - if (cached !== undefined) { - return cached; - } - const parser = new ClassParser(`${joined}:flex`, config, cache, device); - const ir = parser.parse(); - const prefixMatches = ir.kind !== `null`; - cache.setPrefixMatch(joined, prefixMatches); - return prefixMatches; - }; - - tailwindFn.setWindowDimensions = (newDimensions: { width: number; height: number }) => { - device.windowDimensions = newDimensions; - cacheGroup = deriveCacheGroup(); - }; - - tailwindFn.setFontScale = (newFontScale: number) => { - device.fontScale = newFontScale; - cacheGroup = deriveCacheGroup(); - }; - - tailwindFn.setPixelDensity = (newPixelDensity: 1 | 2) => { - device.pixelDensity = newPixelDensity; - cacheGroup = deriveCacheGroup(); - }; - - tailwindFn.setColorScheme = (newColorScheme: RnColorScheme) => { - device.colorScheme = newColorScheme; - cacheGroup = deriveCacheGroup(); - }; - - return tailwindFn; -} +export { create, plugin }; +export type { TailwindFn, TwConfig }; +export { useDeviceContext } from "./hooks"; const tailwind = create(); From b1f4c2063f2c57a7f7ce84c0fcc0095f8cc9aac2 Mon Sep 17 00:00:00 2001 From: Fabian Finke Date: Thu, 18 Nov 2021 19:00:46 +0100 Subject: [PATCH 3/6] chore: run format and lint --- src/ClassParser.ts | 11 +++++++++-- src/create.ts | 38 +++++++++++++------------------------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/ClassParser.ts b/src/ClassParser.ts index ed8a3ae..09e0c26 100644 --- a/src/ClassParser.ts +++ b/src/ClassParser.ts @@ -3,7 +3,14 @@ import lineHeight from './resolve/line-height'; import spacing from './resolve/spacing'; import screens from './screens'; import { TwConfig } from './tw-config'; -import { StyleIR, isOrientation, isPlatform, DeviceContext, ParseContext, Platform } from './types'; +import { + StyleIR, + isOrientation, + isPlatform, + DeviceContext, + ParseContext, + Platform, +} from './types'; import fontFamily from './resolve/font-family'; import { color, colorOpacity } from './resolve/color'; import { border, borderRadius } from './resolve/borders'; @@ -37,7 +44,7 @@ export default class ClassParser { private config: TwConfig = {}, private cache: Cache, device: DeviceContext, - platform: Platform + platform: Platform, ) { this.context.device = device; const parts = input.trim().split(`:`); diff --git a/src/create.ts b/src/create.ts index 6dfbf68..636c341 100644 --- a/src/create.ts +++ b/src/create.ts @@ -1,4 +1,4 @@ -import resolveConfig from "tailwindcss/resolveConfig"; +import resolveConfig from 'tailwindcss/resolveConfig'; import { ClassInput, DependentStyle, @@ -9,14 +9,14 @@ import { StyleIR, DeviceContext, Platform, -} from "./types"; -import { TwConfig } from "./tw-config"; -import Cache from "./cache"; -import ClassParser from "./ClassParser"; -import { parseInputs } from "./parse-inputs"; -import { complete, warn } from "./helpers"; -import { getAddedUtilities } from "./plugin"; -import { removeOpacityHelpers } from "./resolve/color"; +} from './types'; +import { TwConfig } from './tw-config'; +import Cache from './cache'; +import ClassParser from './ClassParser'; +import { parseInputs } from './parse-inputs'; +import { complete, warn } from './helpers'; +import { getAddedUtilities } from './plugin'; +import { removeOpacityHelpers } from './resolve/color'; export function create(customConfig: TwConfig, platform: Platform): TailwindFn { const config = resolveConfig(customConfig as any) as TwConfig; @@ -150,7 +150,7 @@ export function create(customConfig: TwConfig, platform: Platform): TailwindFn { .split(/\s+/g) .map((util) => util.replace(/^(bg|text)-/, ``)) .map((util) => `bg-${util}`) - .join(` `) + .join(` `), ); return typeof styleObj.backgroundColor === `string` ? styleObj.backgroundColor @@ -158,10 +158,7 @@ export function create(customConfig: TwConfig, platform: Platform): TailwindFn { } // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - const tailwindFn = ( - strings: TemplateStringsArray, - ...values: (string | number)[] - ) => { + const tailwindFn = (strings: TemplateStringsArray, ...values: (string | number)[]) => { let str = ``; strings.forEach((string, i) => { str += string + (values[i] || ``); @@ -179,23 +176,14 @@ export function create(customConfig: TwConfig, platform: Platform): TailwindFn { if (cached !== undefined) { return cached; } - const parser = new ClassParser( - `${joined}:flex`, - config, - cache, - device, - platform - ); + const parser = new ClassParser(`${joined}:flex`, config, cache, device, platform); const ir = parser.parse(); const prefixMatches = ir.kind !== `null`; cache.setPrefixMatch(joined, prefixMatches); return prefixMatches; }; - tailwindFn.setWindowDimensions = (newDimensions: { - width: number; - height: number; - }) => { + tailwindFn.setWindowDimensions = (newDimensions: { width: number; height: number }) => { device.windowDimensions = newDimensions; cacheGroup = deriveCacheGroup(); }; From b1c920f4c5faca4ae0483a5d4b66457c044864e6 Mon Sep 17 00:00:00 2001 From: Fabian Finke Date: Thu, 18 Nov 2021 19:49:00 +0100 Subject: [PATCH 4/6] test: add test suite covering commonjs imports --- .gitignore | 1 + .npmrc | 2 ++ package.json | 4 +++- src/__tests__/commonjs.spec.ts | 36 ++++++++++++++++++++++++++++++++++ src/index.ts | 15 +++++++------- 5 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 .npmrc create mode 100644 src/__tests__/commonjs.spec.ts diff --git a/.gitignore b/.gitignore index ad85f91..4989fe9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ dist/ node_modules/ jest.config.js *.swp +.twrnc diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..075be88 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +scripts-prepend-node-path=true + diff --git a/package.json b/package.json index b6d174f..4bf3b19 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,9 @@ "ts:check": "fldev ts:check", "format": "fldev format", "format:check": "fldev format --check", - "compile": "fldev ts:compile && fldev ts:compile --project tsconfig.cjs.json", + "compile": "npm run compile:esm && npm run compile:cjs", + "compile:esm": "fldev ts:compile", + "compile:cjs": "fldev ts:compile --project tsconfig.cjs.json", "prepublishOnly": "npm run compile", "npub:precheck": "npm run lint && npm run format:check && npm run ts:check && npm run test" }, diff --git a/src/__tests__/commonjs.spec.ts b/src/__tests__/commonjs.spec.ts new file mode 100644 index 0000000..6abbf0b --- /dev/null +++ b/src/__tests__/commonjs.spec.ts @@ -0,0 +1,36 @@ +import fs from 'fs'; +import path from 'path'; +import { exec as _exec } from 'child_process'; +import { promisify } from 'util'; + +const exec = promisify(_exec); + +describe(`commonjs support`, () => { + const parentDir = path.join(__dirname, `../../.twrnc`); + let tempDir: string; + beforeAll(async () => { + await fs.promises.mkdir(parentDir).catch(() => { + // Ignore if it already exists + }); + + tempDir = await fs.promises.mkdtemp(path.join(parentDir, `cjs-output`)); + + // Compile CommonJS code to a temporary directory in .twrnc + await exec(`npm run compile:cjs -- --outDir "${tempDir}"`, { + cwd: path.join(__dirname, `../../`), + }); + }); + + afterAll(async () => { + // Cleanup compilation output from temp directory + await fs.promises.rmdir(tempDir, { + recursive: true, + // @ts-ignore - Required for Node 12 + force: true, + }); + }); + + test(`\`create\` can be required from node`, async () => { + await exec(`node -e 'require("${tempDir}/create")'`); + }); +}); diff --git a/src/index.ts b/src/index.ts index 267e4eb..77e5219 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,16 +1,15 @@ -import { Platform } from "react-native"; -import { TailwindFn } from "./types"; -import { TwConfig } from "./tw-config"; -import plugin from "./plugin"; -import rawCreate from "./create"; +import { Platform } from 'react-native'; +import { TailwindFn } from './types'; +import { TwConfig } from './tw-config'; +import plugin from './plugin'; +import rawCreate from './create'; // Apply default config and inject RN Platform -const create = (twConfig: TwConfig = {}): TailwindFn => - rawCreate(twConfig, Platform.OS); +const create = (twConfig: TwConfig = {}): TailwindFn => rawCreate(twConfig, Platform.OS); export { create, plugin }; export type { TailwindFn, TwConfig }; -export { useDeviceContext } from "./hooks"; +export { useDeviceContext } from './hooks'; const tailwind = create(); From 6f83611680ab2aa86b26dc6729e43056dca2a053 Mon Sep 17 00:00:00 2001 From: Fabian Finke Date: Thu, 18 Nov 2021 20:47:03 +0100 Subject: [PATCH 5/6] fix submodule import and type detection --- package.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/package.json b/package.json index 4bf3b19..8fe444b 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,21 @@ "module": "dist/esm/index.js", "types": "dist/esm/index.d.ts", "main": "dist/cjs/index.js", + "exports": { + ".": { + "import": "./dist/esm/index.js", + "require": "./dist/cjs/index.js" + }, + "./create": { + "import": "./dist/esm/create.js", + "require": "./dist/cjs/create.js" + } + }, + "typesVersions": { + "*": { + "create": ["./dist/esm/create.d.ts"] + } + }, "license": "MIT", "scripts": { "test": "jest", From c9048e38ceefe885655cd1c3c44f1bed0ed8b74f Mon Sep 17 00:00:00 2001 From: Jared Henderson Date: Fri, 19 Nov 2021 16:26:10 -0500 Subject: [PATCH 6/6] move test for node commonjs compat into gh action ci --- .github/workflows/ci.yml | 2 ++ .gitignore | 1 - src/__tests__/commonjs.spec.ts | 36 ---------------------------------- 3 files changed, 2 insertions(+), 37 deletions(-) delete mode 100644 src/__tests__/commonjs.spec.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94c240a..b2d15c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,8 @@ jobs: run: npm run ts:check - name: compile run: npm run compile + - name: check commonjs node compat + run: node ./dist/cjs/create.js - name: lint run: npm run lint - name: test diff --git a/.gitignore b/.gitignore index 4989fe9..ad85f91 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ dist/ node_modules/ jest.config.js *.swp -.twrnc diff --git a/src/__tests__/commonjs.spec.ts b/src/__tests__/commonjs.spec.ts deleted file mode 100644 index 6abbf0b..0000000 --- a/src/__tests__/commonjs.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import { exec as _exec } from 'child_process'; -import { promisify } from 'util'; - -const exec = promisify(_exec); - -describe(`commonjs support`, () => { - const parentDir = path.join(__dirname, `../../.twrnc`); - let tempDir: string; - beforeAll(async () => { - await fs.promises.mkdir(parentDir).catch(() => { - // Ignore if it already exists - }); - - tempDir = await fs.promises.mkdtemp(path.join(parentDir, `cjs-output`)); - - // Compile CommonJS code to a temporary directory in .twrnc - await exec(`npm run compile:cjs -- --outDir "${tempDir}"`, { - cwd: path.join(__dirname, `../../`), - }); - }); - - afterAll(async () => { - // Cleanup compilation output from temp directory - await fs.promises.rmdir(tempDir, { - recursive: true, - // @ts-ignore - Required for Node 12 - force: true, - }); - }); - - test(`\`create\` can be required from node`, async () => { - await exec(`node -e 'require("${tempDir}/create")'`); - }); -});