Skip to content

Instantly share code, notes, and snippets.

@agwells
Last active September 30, 2019 21:17
Show Gist options
  • Save agwells/1606d1bc45dddb782ca8d336b6802e90 to your computer and use it in GitHub Desktop.
Save agwells/1606d1bc45dddb782ca8d336b6802e90 to your computer and use it in GitHub Desktop.
Executing code written for Create React App, as a CLI
/**
* This file is the "Launch" script for running Create React App code at the command
* line. It calls "@babel/register", which is a Babel utility that hijacks
* the normal node "require()" function and lets Babel pre-compile imported
* files into Node-compatible JS before they're executed.
*
* This bootstraps up the fancy CRA TypeScript/React configuration (using the
* Babel config imported from "babel-preset-react-app"). Then it simply "require()"s
* some other JS/TS/JSX/TSX file, and executes it.
*
* To execute:
*
* > node cracli.js
*
* NOTE: Another approach would be to rely on CRA's webpack configuration, modified
* to include your CLI script(s) as another entry point, and the "node" target.
*/
// Ensure environment variables are read.
// We need to tell CRA to use the "test" environment so it will make everything
// command-line friendly.
// @ts-ignore
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';
const defaultResolver = require('babel-plugin-module-resolver').resolvePath;
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', (err) => {
throw err;
});
const config = {
// THIS LINE is the important one. "babel-preset-react-app" is the Babel
// configuration that Create React App uses! Importing this, while specifying
// that NODE_ENV = "test", automatically gives us the same Babel configuration
// that CRA uses when executing Jest tests in the CLI.
//
// NOTE we still have to tweak a couple of additional things, which CRA
// takes care of through Webpack on the browser-side, and through Jest configs
// on the CLI.
presets: ['babel-preset-react-app'],
// Tell Babel which file extensions to try to compile. (Note that it will
// by default ignore files imported from node_modules, which is good.)
extensions: ['.js', '.jsx', '.ts', '.tsx'],
plugins: [
[
'babel-plugin-module-resolver',
{
// Simulate our "absolute" import paths, e.g. using
// "import 'components/base/button';" instead of
// "import '../../../../components/base/button';"
// CRA does this by examining our tsconfig.json file and then configuring
// Webpack (for browser) or a "--modules" flag (for Jest)
root: ['./src/'],
extensions: [
// Code files
'.js',
'.jsx',
'.ts',
'.tsx',
// Files to replace with empty placeholders
'.scss',
'.css',
'.svg',
'.png',
],
// Ignore the CSS/SVG import syntax "import 'button.scss';"
// Specifically, the import is still there, but we rewrite it to import
// an empty file.
resolvePath(sourcePath, currentFile, opts) {
if (/\.(scss|css|svg|png)$/.test(sourcePath)) {
// NOTE: Need to make an empty file called "emptyfile.js" for this to work.
// TODO: Simulate CRA's ability to inline small image files as data URIs.
return defaultResolver('emptyfile', currentFile, opts);
} else {
return defaultResolver(sourcePath, currentFile, opts);
}
},
},
],
],
};
// NOTE: Using @babel/register is convenient during development, because it recompiles
// things on the fly. But for production you would probably want to compile things
// and execute the compiled code.
require('@babel/register')(config);
require('./SOMEFILE.tsx');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment