-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add support for
jsxImportSource
, new JSX transform
- Loading branch information
Nate Moore
committed
Jul 20, 2021
1 parent
b9c5b7e
commit 077c4bf
Showing
12 changed files
with
347 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
tap "homebrew/bundle" | ||
tap "homebrew/core" | ||
brew "fnm" | ||
brew "fzf" | ||
brew "gh" | ||
brew "git" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/** @jsxImportSource preact */ | ||
|
||
/** a counter written in Preact */ | ||
export default function PreactSFC({ children }) { | ||
return ( | ||
<> | ||
<div className="counter"> | ||
Hello from Preact! | ||
</div> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
const esbuild = require('esbuild'); | ||
const colors = require('kleur/colors'); | ||
const { logger } = require('snowpack'); | ||
const path = require('path'); | ||
const { promises: fs } = require('fs'); | ||
|
||
const babel = require('@babel/core') | ||
const babelPluginTransformJsx = require('@babel/plugin-transform-react-jsx').default; | ||
const eslexer = require('es-module-lexer'); | ||
|
||
/** | ||
* @typedef {Object} PluginOptions - creates a new type named 'SpecialType' | ||
* @prop {import('./src/config_manager').ConfigManager} configManager | ||
* @prop {'development' | 'production'} mode | ||
*/ | ||
|
||
/** | ||
* Returns esbuild loader for a given file | ||
* @param filePath {string} | ||
* @returns {import('esbuild').Loader} | ||
*/ | ||
function getLoader(filePath) { | ||
/** @type {any} */ | ||
const ext = path.extname(filePath); | ||
return ext.substr(1); | ||
} | ||
|
||
const transformJsx = ({ code, filePath: filename, sourceMap: sourceMaps }, importSource) => { | ||
return babel.transformSync(code, { | ||
filename, | ||
plugins: [ | ||
babelPluginTransformJsx({}, { runtime: 'automatic', importSource }) | ||
], | ||
sourceMaps, | ||
} | ||
) | ||
} | ||
|
||
/** | ||
* @type {import('snowpack').SnowpackPluginFactory<PluginOptions>} | ||
*/ | ||
module.exports = function jsxPlugin(config, options = {}) { | ||
const { | ||
configManager | ||
} = options; | ||
|
||
let didInit = false; | ||
return { | ||
name: '@astrojs/snowpack-plugin-jsx', | ||
resolve: { | ||
input: ['.jsx', '.tsx'], | ||
output: ['.js'], | ||
}, | ||
async load({ filePath }) { | ||
if (!didInit) { | ||
await eslexer.init; | ||
didInit = true; | ||
} | ||
|
||
const contents = await fs.readFile(filePath, 'utf8'); | ||
const loader = getLoader(filePath); | ||
|
||
const { code, warnings } = await esbuild.transform(contents, { | ||
loader, | ||
jsx: 'preserve', | ||
sourcefile: filePath, | ||
sourcemap: config.buildOptions.sourcemap ? 'inline' : undefined, | ||
charset: 'utf8', | ||
sourcesContent: config.mode !== 'production', | ||
}); | ||
for (const warning of warnings) { | ||
logger.error(`${colors.bold('!')} ${filePath} | ||
${warning.text}`); | ||
} | ||
|
||
let renderers = await configManager.getRenderers(); | ||
const importSources = new Set(renderers.map(({ jsxImportSource }) => jsxImportSource).filter(i => i)); | ||
|
||
// If we only have a single renderer, we can skip a bunch of work! | ||
if (importSources.size === 1) { | ||
const result = transformJsx({ | ||
code, | ||
filePath, | ||
sourceMap: config.buildOptions.sourcemap ? 'inline' : false, | ||
}, Array.from(importSources)[0]) | ||
|
||
return { | ||
'.js': { | ||
code: result.code || '' | ||
}, | ||
}; | ||
} | ||
|
||
// we need valid JS to scan for imports | ||
// so let's just use `h` and `Fragment` as placeholders | ||
const { code: codeToScan } = await esbuild.transform(code, { | ||
loader: 'jsx', | ||
jsx: 'transform', | ||
jsxFactory: 'h', | ||
jsxFragment: 'Fragment', | ||
}); | ||
|
||
const [imports] = eslexer.parse(codeToScan); | ||
let importSource; | ||
|
||
if (imports) { | ||
for (let { n: name } of imports) { | ||
if (name.indexOf('/') > -1) name = name.split('/')[0]; | ||
if (importSources.has(name)) { | ||
importSource = name; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
if (!importSource) { | ||
let match; | ||
|
||
while ((match = /\/\*\*(?:[^*][^/]|\s)*@jsxImportSource\s+(.+)\s*\*\//gm.exec(contents)) !== null) { | ||
importSource = match[1].trim(); | ||
break; | ||
} | ||
} | ||
|
||
if (!importSource) { | ||
console.log(`${filePath} | ||
Unable to resolve JSX transformer! If you have more than one renderer enabled, you should use a pragma comment. | ||
/* jsxImportSource: preact */ | ||
`); | ||
return { | ||
'.js': { | ||
code: '' | ||
}, | ||
} | ||
} | ||
|
||
const result = transformJsx({ | ||
code, | ||
filePath, | ||
sourceMap: config.buildOptions.sourcemap ? 'inline' : false, | ||
}, importSource) | ||
|
||
return { | ||
'.js': { | ||
code: result.code || '' | ||
}, | ||
}; | ||
}, | ||
cleanup() {}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.