Let’s kick things off by applying an Ember lens to application structure and tooling in React.
React appears as the sprawling forest outside the walls of Ember’s orderly garden. Ember developers who leave their comfort zone to work in React might be heard complaining about the lack of structure and conventions. It is a mixed blessing to have such conventions (also called “opinions”). The Emberista who brings a mental model of a “perfect” Ember App — each file in its correct place, properly named, in harmony — will see anti-patterns and know in their gut that there must be a better way.
React shifts our focus to the component. In fact, there is no React “application” in the way that Ember people expect. React is nothing but a collection of components. Everything else is external and optional. The concerns of state management, testing, API requests, and even the pipelines for building and deploying the “app” are all outside of React, and can be assembled by any number of third-party libraries or hand-rolled.
If Ember is an Olympic-regulation swimming pool, React is a rushing river.
The Philosophy of each framework is apparent in their Blueprints
Every modern Ember app begins with
React has no such structure. There is a glut of “starter kits” available, each with a different philosophy or collection of add-ons. The most popular of these is the
create-react-app tool, which is maintained by the React team at Facebook.
create-react-app is not ember-cli. It drops you into a shiny new React project with most of the complexity obscured from your sight. In this initial state, there is no configuration required. Dependencies and development tools are tucked away inside of the ‘react-scripts’ package. You do get a default serviceWorker.js file and manifest.json, which allows your React App to act as a Progressive Web App or “PWA”. I would like to see this in the
ember new blueprint.
create-react-app is enough for some projects, at least for a while. When the project outgrows the training wheels, one simply executes
npm run eject. This command performs the irreversible step of revealing all the ugly dependencies and configuration files and dumping them into your folder for you to edit. As of this writing,
eject will result in the addition of nine config files, three scripts, and 52 new dependencies in package.json. This “ejected” form is a good template of a default or “conventional” React app. I will use this as a basis of comparison against Ember’s default structure.
At first glance, the files look pretty similar
The two apps have much in common. Both have a README.md, a package.json, a public/ folder, and a config/ folder. React puts its application code in src/, Ember puts it in app/. Ember has a tests/ folder. React puts its test files in src/ with the other code.
Within the app/ folder of an Ember app, we have components/, controllers/, helpers/, models/, routes/, styles/, and templates/ sub-folders. There are a few alternatives to this organizing structure, but with Ember it is much easier to follow the convention than to fight against it. In the React src/ folder there are no subfolders. It is totally up to you to organize your source code how you see fit. There are no module generators or naming conventions like Ember has. Every React app is different.
The “Ember Way” can be very empowering
Every Ember app starts with ember-cli. Many React projects do not start with create-react-app. In fact, you can add React.js to any project by just installing the npm library or even adding a link to the CDN-hosted library into an HTML file. This is not possible with Ember. Ember is all-or-nothing. One does not simply “sprinkle” ember.js into an existing project. CDN-distributed Ember has been discontinued long ago because ember.js and ember-cli and the whole Ember application structure are all interdependent.
This probably feels grotesque to a React engineer, but within the walled garden of Emberland, it is empowering.
The “Ember Way” is so commonplace that it is almost invisible. Most Ember projects spend little to no thought on their build configurations (contrast with React & Webpack). Ember add-ons can take advantage of Ember application structure conventions and make assumptions that hold true for nearly every Ember app. Improvements to security, build efficiency, linting, test running, and more can be achieved in a centralized way within the Ember community and propagated outward, via ember-cli versions and blueprints, and gain near-universal adoption.
React apps come in many shapes and flavors
The React community is free to develop and experiment with an astounding variety of tools, libraries, and approaches. There does seem to be more innovation, more pushing of boundaries, and testing the limits of what can be done with modern web application development.
It is not surprising that we see React at the forefront of Serverless implementations, Progressive Web Apps, and mobile apps. To an Ember engineer, this can either be a terrifying or a deeply liberating experience. If you don’t like something, you change it, or hack around it, or build something new. Each company, team, or individual contributor is empowered to become a React pioneer and to find their own pattern. Over time, best practices become codified and make their way up the hill to be enshrined into the most popular patterns: create-react-app, Next.js, Gatsby.js, and the like.
Ember has a built-in test interface; React has Jest
In a create-react-app project, one can use
npm run build to generate a build/ folder that is “ready to be deployed”. This is similar to
ember build -prod except Ember doesn’t use webpack, and Ember outputs its assets to a dist/ folder. In the React app
npm test will run a nice terminal-based test interface, using jest. Jest is unfamiliar to many Ember developers, but it is a great test library from the React team at Facebook. It is not React-specific and can be used with Node or other frameworks. The ejected create-react-app injects a bunch of Jest configuration into the package.json file.
By contrast, Ember comes with a customized QUnit installation, that can be run headlessly in the terminal or in a brilliant browser UI hosted at localhost:4200/tests. Ember emphasizes testing and builds tests into its blueprints. React does not do this. Testing approaches vary considerably from one React app to another.
Ember & React both have a fast reloading development server
The create-react-app project configures
npm start to run a webpack dev server, open a browser to localhost:3000, and watch for file changes to update via Hot Module Reloading (HMR). This is extremely similar to Ember’s
npm start or
Ember-CLI stays with you; create-react-app lets you go
Ember-CLI does not have an analogy to the
eject of create-react-app. You can continue to update Ember, ember-cli, and your application boilerplate (using
ember-cli-update) with each new version. A create-react-app project can be easily updated as long as you don’t eject it. Once it is ejected you are on your own to manage everything yourself. This, more than anything, is emblematic of the “React Way” as opposed to the “Ember Way”.
An Ember developer who is striving to understand React should not search too hard for dogma and guardrails but should embrace the freedom of possibility. React puts its developers in the driver’s seat to go wherever they please with the tools available. Even if that means going off-road into uncharted territory.
DockYard is a digital product consultancy specializing in user-centered web application design and development. Our collaborative team of product strategists help clients to better understand the people they serve. We use future-forward technology and design thinking to transform those insights into impactful, inclusive, and reliable web experiences. DockYard provides professional services in strategy, user experience, design, and full-stack engineering using Ember.js, React.js, Ruby, and Elixir. From ideation to delivery, we empower ambitious product teams to build for the future.