vue.jsbabeljsvue-cli-3babel-loaderterser

Can't remove `console` statements with babel nor terser in vue cli 3 / 4, but second build run works


I'm having issues with npm run build, which effectively calls vue-cli-service build. My goal is to remove console statements in production builds. However, the first time it fails. If I run it again immediately (without code changes), it succeeds.

For reproducibility and isolation, I'm running code in a node docker:

docker run --rm -it -v "$(pwd):/usr/src/app" node:14.4.0 /bin/bash

In the docker I setup the environment

npm ci

In the clean environment, running the build fails:

root@bd366b5873ca:/usr/src/app# npm run build

> my-app@0.1.0 build /usr/src/app
> vue-cli-service build

PRODUCTION babel setup
production eslint setup.

⠦  Building for production...production eslint setup.
⠇  Building for production...PRODUCTION babel setup
⠼  Building for production...production eslint setup.
⠙  Building for production...

 ERROR  Failed to compile with 8 errors    

The errors are all eslint errors on occurrences of console. commands:

Module Error (from ./node_modules/eslint-loader/index.js):
error: Unexpected console statement (no-console) at XXXX

Immediately running the build again, results in a successful build:

root@bd366b5873ca:/usr/src/app# npm run build

> my-app@0.1.0 build /usr/src/app
> vue-cli-service build

PRODUCTION babel setup
production eslint setup.

⠏  Building for production...

 WARNING  Compiled with 2 warnings    

The PRODUCTION babel setup and production eslint setup originate from my babel.config.js and .eslint.rc.

I've configured eslint as follows, to fail on console. statements in production:

# .eslintrc.js
if (process.env.NODE_ENV === 'production') {
  console.info('production eslint setup.')
}
module.exports = {
  root: true,

  env: {
    node: true
  },

  'plugins': ['jest'],

  'extends': [
    'eslint:recommended',
    'plugin:vue/recommended',
    '@vue/standard',
    'plugin:jest/recommended',
    'plugin:jest/style'
  ],

  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
  },

  parserOptions: {
    parser: 'babel-eslint',
    parserOptions: {
      babelOptions: {
        configFile: "babel.config.js"
      }
    }
  }

}

I've configured babel to remove the console. statements:

# babel.config.js
/* eslint-disable no-var */
module.exports = (api) => {
  var isProd = api.cache.invalidate(() => process.env.NODE_ENV === 'production')
  var plugins = []
  if (isProd) {
    console.info('PRODUCTION babel setup')
    plugins.push(['transform-remove-console', { exclude: [] }])
  }
  return {
    presets: ['@vue/cli-plugin-babel/preset'],
    plugins
  }
}

In attempts to get it fixed, I've also configured terser to remove console. statements:

# vue.config.js
module.exports = {
  'transpileDependencies': [
    'vuetify'
  ],
  publicPath: process.env.PUBLIC_SUB_PATH === ''
    ? '/' : '/' + process.env.PUBLIC_SUB_PATH + '/',
  runtimeCompiler: true,
  css: {
    extract: { ignoreOrder: true }
  },
  chainWebpack: config => {
    config.optimization.minimize = true
    config.optimization.minimizer('terser').tap((args) => {
      args[0].terserOptions.compress.drop_console = true
      return args
    })
  }
}

Versions (from package.json). In attempt to fix it, upgraded to vue-cli 4, also happened in vue-cli 3:

....
"dependencies": {
    "axios": "^0.19.2",
    "core-js": "^3.6.5",
    "vue": "^2.6.11",
    "vue-router": "^3.3.4",
    "vuetify": "^2.3.1",
    "vuex": "^3.4.0"
  },
....
"devDependencies": {
    "@babel/core": "^7.10.3",
    "@babel/preset-env": "^7.10.3",
    "@vue/cli-service": "^4.4.4",
    "babel-eslint": "^10.1.0"
    "babel-loader": "^8.1.0",
    "babel-plugin-transform-remove-console": "^6.9.4",
    "eslint": "^5.16.0",
    ...
}

Question:

The console prints of PRODUCTION babel setup and production eslint setup show that in a clean build, the configuration is loaded multiple times. Then it fails somehow. Running it again seems more straightforward, configs are loaded once and then it succeeds.

How can I configure vue to successfully build the first time, removing the console statements?


Is it the cache?

After the successsful build, removing the cache:

rm -Rf ./node_modules/.cache

and then building it again (npm run build) is equal to the first run: fails


Modern build?

When creating a modern build (after a npm run build to populate the cache):

 npm run build -- --modern

Successfully builds the legacy build, but fails the modern build:

> my-app@0.1.0 build /usr/src/app
> vue-cli-service build "--modern"

PRODUCTION babel setup
production eslint setup.

⠏  Building legacy bundle for production...

 WARNING  Compiled with 2 warnings          

....
PRODUCTION babel setup
production eslint setup.

⠹  Building modern bundle for production...PRODUCTION babel setup
⠧  Building modern bundle for production...PRODUCTION babel setup
⠋  Building modern bundle for production...PRODUCTION babel setup
⠏  Building modern bundle for production...PRODUCTION babel setup
PRODUCTION babel setup
⠹  Building modern bundle for production...PRODUCTION babel setup
⠧  Building modern bundle for production...PRODUCTION babel setup
⠦  Building modern bundle for production...

 ERROR  Failed to compile with 3 errors 

Module Error (from ./node_modules/thread-loader/dist/cjs.js):

/usr/src/app/src/axios.js
   7:3  error  Unexpected console statement  no-console

Running the modern build again immediately after it succeeds successfully. So I need in total 3 runs for the modern build to succeed (first time legacy bundle fails, second time legacy bundle succeeds but modern build fails, third time legacy and modern build succeed).

Vue issue

There is a related vue issue at https://github.com/vuejs/vue-cli/issues/5399


Solution

  • I met the same err and i fixed it through adding lintOnSave: process.env.NODE_ENV === 'development' in vue.config.js. The following is the checklist to help u fix ur problem:

    About lintOnsave