DEV Community

Cover image for The difference between ember serve and npm run start
Jessy Jordan
Jessy Jordan

Posted on • Edited on

The difference between ember serve and npm run start

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?

What npm run start is used for

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.

Sometimes ember serve and npm run start don't behave the same way

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
Enter fullscreen mode Exit fullscreen mode

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)
// ...
Enter fullscreen mode Exit fullscreen mode

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();
};
Enter fullscreen mode Exit fullscreen mode

...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
Enter fullscreen mode Exit fullscreen mode

...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
Enter fullscreen mode Exit fullscreen mode

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?

How Node, NVM and Ember CLI work together

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
Enter fullscreen mode Exit fullscreen mode

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 
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!

So what's the difference between ember serve and 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?"

Top comments (5)

Collapse
 
jelhan profile image
Jeldrik Hanschke

Very helpful insights. Thanks for sharing.

There is one additional difference between npm run start and ember serve: Ember CLI must be installed globally for ember serve to work. npm run start also works with having Ember CLI installed as a project dependency only. This may help with onboarding new developers and to speed up CI. For CI it's most likely not about ember serve but ember test vs. npm run test.

Collapse
 
mattbeiswenger profile image
Matt Beiswenger

You should checkout volta as a replacement for nvm especially for solving some of those issues with global packages.

Collapse
 
jayjayjpg profile image
Jessy Jordan

+1

Collapse
 
maxymczech profile image
Maksym Shcherban

Thank you for the article. It seems this issue isn't specific to ember, but rather would pop up for any npm package installed globally with -g flag.

Collapse
 
jayjayjpg profile image
Jessy Jordan

Yes, exactly!