Repository: nuxt/nuxt.js (ts)

Issue:
incompatible versions warning
We have this feature for `@nuxt/vue-app` dependencies if user-installed version differs from the one with current nuxt version. Now that nuxt2 cannot have upgrades like webpack5 ([sass-loader](https://github.com/nuxt/nuxt.js/issues/8771)), we should create a warning system for well known deps:
- Node.js (to use 12+)
- sass-loader <= 10
- [generic implementation to add more]

Linked: #8782

Pull request description:
feat(cli): warn if incompatible node/package versions detected
## Types of changes
- [x] New feature (a non-breaking change which adds functionality)

## Description
closes #8783

## Checklist:
- [x] I have added tests to cover my changes
- [x] All new and existing tests are passing



Patch:
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 627327743..6db595566 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -31,6 +31,7 @@
     "minimist": "^1.2.5",
     "opener": "1.5.2",
     "pretty-bytes": "^5.5.0",
+    "semver": "^7.3.4",
     "serve-static": "^1.14.1",
     "std-env": "^2.2.1",
     "upath": "^2.0.1",
diff --git a/packages/cli/src/setup.js b/packages/cli/src/setup.js
index 1fba67e2c..3815e8e2d 100644
--- a/packages/cli/src/setup.js
+++ b/packages/cli/src/setup.js
@@ -1,5 +1,6 @@
 import consola from 'consola'
 import exit from 'exit'
+import { checkDependencies } from './utils/dependencies'
 import { fatalBox } from './utils/formatting'
 
 let _setup = false
@@ -15,6 +16,8 @@ export default function setup ({ dev }) {
   }
   _setup = true
 
+  checkDependencies()
+
   // Global error handler
   /* istanbul ignore next */
   process.on('unhandledRejection', (err) => {
diff --git a/packages/cli/src/utils/dependencies.js b/packages/cli/src/utils/dependencies.js
new file mode 100644
index 000000000..18b6f2b69
--- /dev/null
+++ b/packages/cli/src/utils/dependencies.js
@@ -0,0 +1,35 @@
+import consola from 'consola'
+import { satisfies } from 'semver'
+import { getPKG } from '@nuxt/utils'
+
+const dependencies = {
+  postcss: '^7.0.32',
+  webpack: '^4.46.0',
+  'sass-loader': '^10.1.1'
+}
+
+const nodeVersion = '>=12.0.0'
+
+function getInstalledVersion (name) {
+  try {
+    return getPKG(name).version
+  } catch { }
+}
+
+export function checkDependencies () {
+  for (const name in dependencies) {
+    const installedVersion = getInstalledVersion(name)
+    if (!installedVersion) {
+      return // Ignore to avoid false-positive warnings
+    }
+    const expectedRange = dependencies[name]
+    if (!satisfies(installedVersion, expectedRange)) {
+      consola.warn(`${name}@${installedVersion} is installed but ${expectedRange} is expected`)
+    }
+  }
+
+  // Check Node versions
+  if (!satisfies(process.version, nodeVersion)) {
+    consola.warn(`You are using an unsupported version of Node.js (${process.version}). It is recommended to use the latest LTS version (https://nodejs.org/en/about/releases)`)
+  }
+}


Test patch:
diff --git a/packages/cli/test/unit/dependencies.test.js b/packages/cli/test/unit/dependencies.test.js
new file mode 100644
index 000000000..215381216
--- /dev/null
+++ b/packages/cli/test/unit/dependencies.test.js
@@ -0,0 +1,25 @@
+import { consola } from '../utils'
+import { checkDependencies } from '../../src/utils/dependencies'
+
+jest.mock('webpack/package.json', () => ({
+  version: '5.0.0'
+}))
+
+describe('cli/utils', () => {
+  afterEach(() => jest.resetAllMocks())
+
+  test('checkDependencies', () => {
+    checkDependencies()
+    expect(consola.warn).toHaveBeenCalledWith(
+      expect.stringMatching(
+        /webpack@.+ is installed but .+ is expected/
+      )
+    )
+    expect(consola.warn).toHaveBeenCalledTimes(1)
+    if (process.version.startsWith('v10')) {
+      expect(consola.warn).toHaveBeenCalledTimes(2)
+    } else {
+      expect(consola.warn).toHaveBeenCalledTimes(1)
+    }
+  })
+})