Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jonatansberg/ca809eea890fa9fd5d98facd51cde731 to your computer and use it in GitHub Desktop.
Save jonatansberg/ca809eea890fa9fd5d98facd51cde731 to your computer and use it in GitHub Desktop.
Create React App (CRA) with TypeScript and Emotion

Set up CRA with TypeScript and Emotion

Follow the steps below to use babel together with ts-loader so that you can use emotion (or any other Babel plugin) in your React and TypeScript project.

$ create-react-app my-app --scripts-version=react-scripts-ts

2. Add dependencies

$ yarn add emotion react-app-rewired babel-loader babel-preset-env

3. Update scripts in package.json

  "scripts": {
    "start": "react-app-rewired start --scripts-version react-scripts-ts",
    "build": "react-app-rewired build --scripts-version react-scripts-ts",
    "test": "react-app-rewired test --scripts-version react-scripts-ts --env=jsdom",
    "eject": "react-app-rewired eject --scripts-version react-scripts-ts"
  }

4. Set up react-app-rewired (copy config-overrides.js below)

5. Adjust tsconfig (also below)

module.exports = function override(config, env) {
const tsRule = config.module.rules.find(
rule => rule.loader && rule.loader.indexOf('ts-loader') > 0
);
const tsLoader = tsRule.loader;
delete tsRule.loader;
tsRule.use = [
{
loader: require.resolve('babel-loader'),
options: {
plugins: [
// Not using inline mode creates a css file per js/ts file
[require.resolve('emotion/babel'), { inline: true }]
]
}
},
tsLoader
];
return config;
};
{
"compilerOptions": {
"outDir": "build/dist",
"module": "es6",
"target": "es6",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true
},
"exclude": [
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts"
],
"types": [
"typePatches"
]
}
@jonatansberg
Copy link
Author

The babel config probably needs some further changes for production use

@danwoodbury
Copy link

Thanks for the help getting started but I am receiving this error in config-overrides when starting the app:

const tsLoader = tsRule.loader;
                           ^

TypeError: Cannot read property 'loader' of undefined

Any ideas on the issue?

@ALEUT
Copy link

ALEUT commented Oct 28, 2018

Sometimes webpack config created by CRA is changed. You can take a look at current structure using console.log(JSON.stringify(config, null, ' ')); in config-overrides.js. For me it's like this:

function overrideTsLoader(config, env) {
  const oneOfRules = config.module.rules.find(rule => rule.oneOf);
  const tsRule = oneOfRules.oneOf.find(
    rule => rule.use && rule.use.find(
      usage => usage.loader && usage.loader.indexOf('ts-loader') > 0
    )
  );

  const isDev = process.env.NODE_ENV !== 'production';

  tsRule.use.unshift({
    loader: require.resolve('babel-loader'),
    options: {
      plugins: [
        [
          require.resolve('babel-plugin-emotion'), {
          hoist: !isDev,
          autoLabel: isDev,
        }
        ]
      ]
    }
  });

  return config;
}

module.exports = function override(config, env) {
  config = overrideTsLoader(config, env);

  // console.log(JSON.stringify(config, null, ' '));

  return config;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment