22
The difference between ember serve and npm run start
When you have built a single-page-application using Ember CLI, you have two options for starting your app locally. You can either use the CLI's ember serve
command directly or you can use the handy npm
alias that is created for you after generating a new Ember app: npm run start
But what's the difference between those two?
First, npm run start
allows you to create your own default boot up command for your application by e.g. passing additional parameters to ember serve
and hide this modified booting instruction away in one, single, shorthand command via a definition in your package.json
. This makes you type less and can make your life easier when developing your app locally.
If you want to learn more about how to modify the ember serve
command, check out the official Ember CLI Docs.
In a fresh Ember app though, the functionality of both ember serve
and npm run start
will be almost identical. Emphasis on almost.
Recently, while working on one of my side projects, I tried to boot up an Ember application using TailwindCSS by running the ember serve
command. The build process was kicked off, but ultimately failed with the following error message:
Object.entries(...).flatMap is not a function
The stack trace pointed to issues with the PostCSS
compiler I had been using to integrate TailwindCSS with my app's styles:
Object.entries(...).flatMap is not a function
at PostcssCompiler.Plugin (/home/jayjayjpg/Documents/projects/my/project/node_modules/broccoli-plugin/index.js:7:31)
at new CachingWriter (/home/jayjayjpg/Documents/projects/my/project/node_modules/broccoli-caching-writer/index.js:18:10)
at new PostcssCompiler (/home/jayjayjpg/Documents/projects/my/project/node_modules/broccoli-postcss-single/index.js:20:5)
at Object.keys.map (/home/jayjayjpg/Documents/projects/my/project/node_modules/ember-cli-postcss/index.js:36:12)
// ...
After some debugging and double-checking my setup that I have followed from Chris Masters' working example for TailwindCSS in an Ember app in my ember-cli-build.js
was correct:
// ember-cli-build.js
'use strict';
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
const isProduction = EmberApp.env() === 'production';
const purgeCSS = {
module: require('@fullhuman/postcss-purgecss'),
options: {
content: [
// add extra paths here for components/controllers which include tailwind classes
'./app/index.html',
'./app/templates/**/*.hbs',
'./app/components/**/*.hbs'
],
defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
}
}
module.exports = function(defaults) {
let app = new EmberApp(defaults, {
postcssOptions: {
compile: {
plugins: [
{
module: require('postcss-import'),
options: {
path: ['node_modules']
}
},
require('tailwindcss')('./app/tailwind.config.js'),
...isProduction ? [purgeCSS] : []
]
}
}
});
return app.toTree();
};
...I started to do a quick google search, to see if any other folks using TailwindCSS ran into a similar issue.
And indeed, I found a couple of issues here and there that pointed to the fact, that the .flatMap
method used at build time of my application was a more recent feature of Node and only available from Node v11+.
I confirmed that I was still on an older version of Node, that this would explain the lacking support of the .flatMap
function:
node -v
10.16.3
...and was enthusiastic about quickly resolving the build problem with an upgrade of Node. Since I was using nvm my upgrade turned out as follows:
nvm install 14
nvm use 14
rm -rf node_modules/ && npm install
As soon as the installation finished, I tried my luck again by running ember serve
, and to my surprise - the build failed again with the very same .flatMap is not a function
error!
Still in disbelief, I tried running npm run start
instead and lo and behold - my app built successfully?
How could my application build fail when the build command was run directly, but still succeed when its alias was executed?
Once I checked on the versions of my Ember CLI and my Node installs, it became more clear, why npm run start
and ember serve
would behave differently:
node -v
v14.17.1
ember -v
ember-cli: 3.26.1
node: 10.16.3
os: linux x64
How come that Ember CLI was linked to an older version of Node different from my local Node version?
In my case, I've been using nvm
to switch between different versions of Node on my machine.
When using nvm, it's important to be mindful on how this will affect the usage of globally installed packages. Nvm ensures that any global installs of binaries end up in a dedicated, versioned directory of nvm
in the user's HOME
directory. On Linux, you can verify this by checking the Ember CLI's binary location as follows:
whereis ember
ember: /home/jayjayjpg/.nvm/versions/node/v10.16.3/bin/ember
A while ago I had installed Ember CLI globally via npm install -g ember-cli
while on Node 10.16.3. This instructed nvm
to store the binary in the related 10.16.3 Node directory and make it available via this Node version. Now whenever I would run ember serve
on my command line, this outdated binary would be used, running on Node 10.16.3, regardless if I had instructed nvm
to switch to Node v.14.17.1 or not:
# Switching to Node 10.16.3
nvm use 10
node -v
v10.16.3
ember -v
node: 10.16.3
# Switching to Node 14.17.1
nvm use 14
node -v
v14.17.1
ember -v
node: 10.16.3
Whenever I would run npm run start
though, my project's local Ember CLI version would be used leading to a successful app build.
The behavior of ember serve
and npm run start
doesn't have to differ this way though, as nvm
provides you with a command to migrate all of your already existing, global npm installations over to a newer version of Node and make them available when switching to said version:
nvm install 14 --reinstall-packages-from=10
After the migration I could now see my global Ember CLI binary associated with the newer Node version and residing in the path that I'd expect:
whereis ember
ember: /home/jayjayjpg/.nvm/versions/node/v14.17.1/bin/ember
ember -v
ember-cli: 3.26.1
node: 14.17.1
And finally, upon running ember serve
, the app would build successfully using Node v.14.17.1 just as it would using npm run start
!
In a fresh Ember app and in nearly all cases, npm run start
and ember serve
function the exact same way. But if you have a different version of Ember CLI installed globally versus locally or if you're using version managers for Node, the outcome of these two commands may differ from each other.
This post has been inspired by this great response on Stackoverflow to the question "Is there a difference between ember serve
and npm start
?"
22