diff --git a/.gitignore b/.gitignore index c6bba59..7239960 100644 --- a/.gitignore +++ b/.gitignore @@ -96,6 +96,7 @@ dist # Comment in the public line in if your project uses Gatsby and not Next.js # https://nextjs.org/blog/next-9-1#public-directory-support # public +/docs # vuepress build output .vuepress/dist diff --git a/.swcrc b/.swcrc new file mode 100644 index 0000000..3b35253 --- /dev/null +++ b/.swcrc @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "jsc": { + "parser": { + "syntax": "typescript" + }, + "target": "es2020", + "loose": true, + "keepClassNames": true + }, + "minify": false +} diff --git a/README.md b/README.md index 6b3e38e..ecee2b0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # TSX Browser Compiler -Transform a set of `.tsx` file into React element, extremely useful for the "live edit" feature in component library documents. +Transform a set of `.tsx` (as well as other extensions) files into React elements, extremely useful for the "live edit" feature in component library documents. diff --git a/package.json b/package.json index 8ce89a0..9aba8d6 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,9 @@ "scripts": { "start": "cross-env rollup -c rollup.config.pages.ts -w", "dev": "cross-env pnpm start", - "lint:eslint": "eslint --ext .ts,.tsx . --quiet", - "lint:stylelint": "stylelint '**/*.{css,less}' --fix", + "lint:eslint": "cross-env eslint --ext .ts,.tsx . --quiet", + "lint:stylelint": "cross-env stylelint '**/*.{css,less}' --fix", + "build": "cross-env rollup -c", "build:pages": "cross-env NODE_ENV=production BASEDIR=docs rollup -c rollup.config.pages.ts" }, "repository": { diff --git a/playground/index.less b/playground/index.less index b9855fd..ca8b529 100644 --- a/playground/index.less +++ b/playground/index.less @@ -82,71 +82,84 @@ a { font-weight: 500; line-height: var(--playground-controls-height); - & + div { - margin: 0 8px 0 auto; + small { + margin-left: 8px; + font-size: 12px; + font-weight: normal; } - } - - button { - box-sizing: border-box; - margin-right: 8px; - padding: 0 4px; - height: 20px; - background: var(--playground-button-background); - border-radius: 4px; - border: 1px solid var(--playground-divider-color); - color: var(--playground-text-color); - font-size: 12px; - vertical-align: middle; - cursor: pointer; - &:active { - background: var(--playground-button-hover-background); + & + div { + margin: 0 8px 0 auto; } } - label { - position: relative; - display: inline-flex; + &-buttons { + display: flex; align-items: center; - padding: 4px 8px; - font-size: 12px; - input { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - border-radius: 4px; - margin: 0 4px 0 0; - appearance: none; + button { + box-sizing: border-box; + margin-right: 8px; + padding: 4px 4px; background: var(--playground-button-background); + border-radius: 4px; + border: 1px solid var(--playground-divider-color); + color: var(--playground-text-color); + font-size: 12px; + vertical-align: middle; cursor: pointer; - & + span { - z-index: 1; - cursor: pointer; + &:active { + background: var(--playground-button-hover-background); } } - & + label input { - border-left: none; - } + label { + position: relative; + display: inline-flex; + align-items: center; + padding: 4px 8px; + font-size: 12px; - &.checked input { - outline: 2px solid var(--playground-tabs-tab-active-border-color); - z-index: 1; - } + .icon { + z-index: 2; + pointer-events: none; + } - &:first-of-type input { - border-bottom-right-radius: 0; - border-top-right-radius: 0; - } + input { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: var(--playground-button-background); + border: 1px solid var(--playground-divider-color); + border-radius: 4px; + margin: 0 4px 0 0; + appearance: none; + cursor: pointer; + outline: 2px solid transparent; + transition: outline-color 0.2s; + } + + & + label input { + border-left: none; + } + + &.checked input { + outline-color: var(--playground-tabs-tab-active-border-color); + z-index: 1; + } + + &:first-of-type input { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + } - &:last-of-type input { - border-bottom-left-radius: 0; - border-top-left-radius: 0; + &:last-of-type input { + border-bottom-left-radius: 0; + border-top-left-radius: 0; + } } } } @@ -218,17 +231,22 @@ a { background: var(--playground-code-background); } - &-active:before { + &:before { position: absolute; top: 0; right: 0; left: 0; display: block; height: 2px; - background: var(--playground-tabs-tab-active-border-color); + background: transparent; + transition: background 0.2s; content: ''; } + &-active:before { + background: var(--playground-tabs-tab-active-border-color); + } + input { color: var(--playground-text-color); } @@ -401,3 +419,12 @@ a { } } } + +.icon { + --icon-size: 16px; + + display: inline-block; + width: var(--icon-size); + height: var(--icon-size); + color: var(--playground-text-color); +} diff --git a/playground/index.tsx b/playground/index.tsx index 9ca4ece..160b024 100644 --- a/playground/index.tsx +++ b/playground/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; -import { asyncTsxToElement } from '../src'; +import { asyncTsxToElement, VERSION } from '../src'; import CompileResult from './components/compile-result'; import { defaultCodeSet } from './configs'; @@ -13,10 +13,18 @@ import './index.less'; const localStorageKey = 'tsx-browser-compiler-playground-sources'; +const IconSplit = (props: { className?: string; style?: React.CSSProperties }) => ( + + + + + +); + const Playground: React.FC = () => { const [sources, setSources] = React.useState<[string, string][]>(defaultCodeSet); const [loading, setLoading] = React.useState(false); - const [layout, setLayout] = React.useState('horizontal'); + const [layout, setLayout] = React.useState(window.innerWidth < 960 ? 'vertical' : 'horizontal'); const [displayedChildren, setDisplayedChildren] = React.useState(null); const [displayedCompiled, setDisplayedCompiled] = React.useState<[string, string][]>([]); const [displayedErrors, setDisplayedErrors] = React.useState([]); @@ -49,10 +57,7 @@ const Playground: React.FC = () => { (content, meta, callback) => { (window as any).less.render( content, - { - filename: meta.filename, - minimize: true, - }, + { filename: meta.filename }, (err: Error, result: { css: string }) => { if (err) { callback(err, '', meta); @@ -89,26 +94,33 @@ const Playground: React.FC = () => { return (
-

TSX Browser Compiler

-
+

+ TSX Browser Compiler + v{VERSION} +

+
diff --git a/rollup.config.pages.ts b/rollup.config.pages.ts index 8c413ec..2dc1866 100644 --- a/rollup.config.pages.ts +++ b/rollup.config.pages.ts @@ -13,6 +13,14 @@ import ts from 'typescript'; import packageJson from './package.json'; const BASEDIR = process.env.BASEDIR || '.cache'; +const reactFile = process.env.NODE_ENV === 'production' ? 'production.min' : 'development'; + +const globals = { + typescript: 'ts', + react: 'React', + 'react-dom': 'ReactDOM', + 'react-dom/client': 'ReactDOM', +}; const plugins = [ less({ @@ -27,6 +35,7 @@ const plugins = [ TSX Browser Compiler Playground +
- + + + @@ -64,21 +75,8 @@ const plugins = [ swc({ minify: process.env.NODE_ENV === 'production', sourceMaps: process.env.NODE_ENV !== 'production', - jsc: { - parser: { - syntax: 'typescript', - }, - transform: { - react: { runtime: 'automatic' }, - }, - target: 'es2020', - loose: true, - keepClassNames: true, - }, - }), - externalGlobals({ - typescript: 'ts', }), + externalGlobals(globals), ]; if (process.env.NODE_ENV !== 'production') { @@ -102,11 +100,9 @@ export default { file: `${BASEDIR}/index.js`, name: 'Playground', format: 'umd', - globals: { - react: 'React', - 'react-dom': 'ReactDOM', - }, + globals, sourcemap: process.env.NODE_ENV !== 'production', }, + external: Object.keys(globals), plugins, }; diff --git a/rollup.config.ts b/rollup.config.ts new file mode 100644 index 0000000..d5bf7d3 --- /dev/null +++ b/rollup.config.ts @@ -0,0 +1,44 @@ +import commonjs from '@rollup/plugin-commonjs'; +import replace from '@rollup/plugin-replace'; +import resolve from '@rollup/plugin-node-resolve'; +import swc from 'rollup-plugin-swc'; + +import packageJson from './package.json'; + +const plugins = [ + resolve({ + preferBuiltins: true, + extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'], + }), + commonjs(), + replace({ + values: { + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), + __VERSION__: JSON.stringify(packageJson.version), + }, + preventAssignment: true, + }), + swc({ + minify: process.env.NODE_ENV === 'production', + sourceMaps: process.env.NODE_ENV !== 'production', + }), +]; + +const globals = { + 'react': 'React', + 'react-dom': 'ReactDOM', + 'react/jsx-runtime': 'jsx', + 'typescript': 'ts', +}; + +export default { + input: { + index: 'src/index.ts', + }, + output: [ + { dir: './dist', format: 'esm', globals, exports: 'auto' }, + { dir: './dist/cjs', format: 'cjs', globals, exports: 'auto' }, + ], + external: Object.keys(globals), + plugins, +}; diff --git a/src/index.ts b/src/index.ts index b083ce6..7878bc6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,6 +9,9 @@ import { parseSources } from './utils/loaders'; export type * from './types'; +declare const __VERSION__: string; +export const VERSION = __VERSION__; + const errNoCode = new Error('No code emitted.'); const ignoredCode = [ 2307,