I've jumped into using Nx today and so far I love it and intend to keep using it! Just came across the following problem and it looks like it could be an issue with how Nx sets up React apps?
Can use class properties/arrow functions in React components
Defining anything in a React component class (extends React.Component) fails with:
ERROR in ./app/app.tsx
Module build failed (from /d/path/node_modules/babel-loader/lib/index.js):
SyntaxError: /d/path/apps/appname/src/app/app.tsx: Missing class properties transform.
Looks like the same as this issue: babel/babel#2729
This comment explains that it's something to do with the order of the babel presets: https://github.com/babel/babel/issues/2729#issuecomment-245401360
npx create-nx-workspace@latest repro-thing --preset=react
Use the following apps/repro-thing/src/app/app.tsx (a simple counter app):
import React from 'react';
import './app.scss';
type Props = {};
type State = {
count: number;
};
export class App extends React.Component<Props, State> {
constructor(props) {
super(props);
this.state = { count: 1 };
}
updateCount = (amount: number) => {
this.setState({ count: this.state.count + amount });
};
render() {
return (
<div className="app">
<h1>counter</h1>
<div>
<button onClick={() => this.updateCount(-1)}>-</button>
{this.state.count}
<button onClick={() => this.updateCount(1)}>+</button>
</div>
</div>
);
}
}
export default App;
Run npm start and wait for "Failed to compile."
I've tried the same code in a React app generated with npx create-react-app thing --typescript and this example works as expected.
"dependencies": {
"document-register-element": "1.13.1",
"react": "16.9.0",
"react-dom": "16.9.0",
"@nestjs/common": "^6.2.4",
"@nestjs/core": "^6.2.4",
"@nestjs/platform-express": "^6.2.4",
"reflect-metadata": "^0.1.12"
},
"devDependencies": {
"@babel/core": "7.5.5",
"@babel/plugin-proposal-decorators": "7.4.4",
"@babel/preset-env": "7.5.5",
"@babel/preset-react": "7.0.0",
"@babel/preset-typescript": "7.3.3",
"@nestjs/schematics": "^6.3.0",
"@nestjs/testing": "^6.2.4",
"@nrwl/cypress": "8.4.13",
"@nrwl/eslint-plugin-nx": "8.4.13",
"@nrwl/jest": "8.4.13",
"@nrwl/nest": "^8.4.13",
"@nrwl/node": "8.4.13",
"@nrwl/react": "8.4.13",
"@nrwl/web": "8.4.13",
"@nrwl/workspace": "8.4.13",
"@testing-library/react": "8.0.5",
"@types/jest": "24.0.9",
"@types/node": "~8.9.4",
"@types/react": "16.9.1",
"@types/react-dom": "16.8.5",
"@typescript-eslint/eslint-plugin": "2.0.0-alpha.4",
"@typescript-eslint/parser": "2.0.0-alpha.4",
"babel-loader": "8.0.6",
"babel-plugin-macros": "2.6.1",
"concurrently": "^4.1.2",
"core-js": "3.1.4",
"cypress": "3.4.1",
"dotenv": "6.2.0",
"eslint": "6.1.0",
"eslint-config-prettier": "6.0.0",
"eslint-plugin-import": "2.18.2",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-react": "7.14.3",
"eslint-plugin-react-hooks": "1.6.1",
"jest": "24.1.0",
"prettier": "1.16.4",
"regenerator-runtime": "0.13.3",
"ts-jest": "24.0.0",
"ts-node": "~7.0.0",
"tslint": "~5.11.0",
"typescript": "~3.4.5"
}

Changing the function to a normal class function and then binding this function to the scope rather than defining an arrow function works, e.g.:
constructor(props) {
super(props);
this.state = { count: 1 };
this.updateCount = this.updateCount.bind(this);
}
updateCount(amount: number) {
this.setState({ count: this.state.count + amount });
};
but this means you have to bind every method, which I'd rather avoid.
This error also occurs for other value types, e.g. numbers:
export class App extends React.Component<Props, State> {
thing = 1
constructor(props) {
...
Gives the following command-line error:
[ui] ERROR in ./app/app.tsx
[ui] Module build failed (from /d/path/node_modules/babel-loader/lib/index.js):
[ui] SyntaxError: /d/path/apps/appname/src/app/app.tsx: Missing class properties transform.
[ui] 10 |
[ui] 11 | export class App extends React.Component<Props, State> {
[ui] > 12 | thing = 1
[ui] | ^
[ui] 13 |
[ui] 14 | constructor(props) {
[ui] 15 | super(props);
@jmsv thanks for checking out Nx and submitting the issue. We will look into it and hopefully land a fix in the next release.
As for now, I found the following solution:
npm install --save-dev babel-plugin-transform-class-properties"use strict";
// Object.defineProperty(exports, "__esModule", { value: true });
const getBabelWebpackConfig = require('@nrwl/react/plugins/babel');
module.exports = function (config) {
const cfg = getBabelWebpackConfig(config);
var idx = cfg.module.rules.findIndex(function (r) {
return r.use && r.use.loader === 'babel-loader';
});
var rule = cfg.module.rules[idx];
if (rule) {
rule.use.options.plugins = [
require('babel-plugin-macros'),
[require('@babel/plugin-proposal-decorators').default, {
legacy: true
}], // enable TS decorators\annotations
require('babel-plugin-transform-class-properties') // hotfix error: "Missing class properties transform"
];
cfg.module.rules.splice(idx, 1, rule);
} else {
console.warn('!!!!!!!!! ATTENTION !!!!!!!!');
console.warn('* Invalid NRWL build process override *');
console.warn('* Please take a look at ' + __filename + ' *');
console.warn('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
}
return cfg;
};
projects.<appname>.architect.build.options.webpackConfig as
...
"webpackConfig": "./tools/build/@babel-react/babel.js"
...
thanks for checking out Nx and submitting the issue. We will look into it and hopefully land a fix in the next release.
awesome, thanks @vsavkin!
@nikita-yaroshevich that works perfectly for now, thanks for the quick response! now to work out step 4 馃槃
@jmsv This will be fixed in the next release (soon!), and then you won't need the custom webpack config. :)
Specifically in this PR #1792.
@jaysoo Maybe you will add TS decorators support for React Apps? Or it out of the scope?
@jaysoo awesome! thanks guys :fire:
@nikita-yaroshevich We can add the support for decorators.
@nikita-yaroshevich decorators will be supported in the next release. https://github.com/nrwl/nx/pull/1798
@jaysoo I am using NX with NextJS and several react libraries that are run with Storybook. The exact same error as mentioned above appears when I run Storybook, but not for NextJS. Could it be that the fix did not apply to Storybook installs? I tried to fix it with the hotfix above and custom .babelrc configurations, but could not get it to work. Thanks for your help!
@jhlabs were you able to resolve this? I'm running into the same thing. LibB storybook imports a Component from LibA
@countravioli unfortunately not. I rewrote my components to functional ones to avoid this issue, but that will not be a solution for most codebases 馃檭
I am facing the same issue with @jhlabs. Storybook breaks with Missing class properties transform.. Kind of blocked with this one as we can't refactor all our components to functional components.
@kimon89, @jhlabs Guys try something like this webpack.config.js
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const rootWebpackConfig = require('../../../.storybook/webpack.config');
// Export a function. Accept the base config as the only param.
module.exports = async ({ config, mode }) => {
config = await rootWebpackConfig({ config, mode });
const tsPaths = new TsconfigPathsPlugin({
configFile: './tsconfig.json',
});
config.resolve.plugins
? config.resolve.plugins.push(tsPaths)
: (config.resolve.plugins = [tsPaths]);
config.resolve.extensions.push('.tsx');
config.resolve.extensions.push('.ts');
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-typescript',
],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
],
},
});
// This is needed for "@storybook/addon-storysource.
// Without this story source code won't show in storybook.
config.module.rules.push({
test: /\.stories\.(ts|tsx)?$/,
loaders: [
require.resolve('@storybook/source-loader'),
],
enforce: 'pre',
});
return config;
};
adding
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
],
solve problem for me.
Most helpful comment
@jaysoo I am using NX with NextJS and several react libraries that are run with Storybook. The exact same error as mentioned above appears when I run Storybook, but not for NextJS. Could it be that the fix did not apply to Storybook installs? I tried to fix it with the hotfix above and custom
.babelrcconfigurations, but could not get it to work. Thanks for your help!