Conditionally import conditionally existing file in Vue

Viewed 1224

I need to import a file into my project when an environment variable is set, say dist/built.esm.js. It's implied that when the environment variable is set, the file will exist, otherwise it may or may not exist. It seems straightforward to just wrap a call to import in an if statement that checks for the environment variable, but Vue throws the below warning even if the if statement never passes:

Screenshot of compile error

And the code:

if (process.env.VUE_APP_USE_COMPILED == 'true') {
    const compiledPackage = require('./dist/built.esm.js')
    Vue.use(compiledPackage)
}

Setting the if statement to always be false in a nondeterminate way (setting a string var and then comparing it to a different value, instead of just if (false)) results in the same problem, which rules out any possibility of the environment variable being 'true' when it isn't supposed to be.

A temporary workaround I found is to wrap the import in a try/catch, which instead displays a warning instead of an error:

Screenshot of compile warning

How can I get rid of the errors and warnings completely? I do want it to still error if the file doesn't exist but the environment variable has been set to true, but it shouldn't fail or warn on compilation if the statement hasn't even executed yet.

3 Answers

Does this work?

if (process.env.VUE_APP_USE_COMPILED == 'true') {
  import('dist/built.esm.js')
    .then(obj => Vue.use(obj))
    .catch(err => console.log(err));
}

but it shouldn't fail or warn on compilation if the statement hasn't even executed yet

Compilation happens before execution. If you get a compile error, that means something went wrong before your code was executed, including any conditionals.

What I believe happens here is that you're using webpack, and it's trying to include dist/built.esm.js in your bundle. Behind the scenes, webpack actually replaces require with some magic. To get around this, use __non_webpack_require__ instead

You could try setting up a compile-time constant using DefinePlugin in your webpack config, maybe something like

plugins: [
    new webpack.DefinePlugin({
        // this is resolved compile-time
        USE_COMPILED: process.env.VUE_APP_USE_COMPILED == 'true'
    })
]

Then, in your code

if (USE_COMPILED) require('./dist/built.esm.js')

Here the value of USE_COMPILED should be replaced by webpack compile-time with true if your environment var is set to 'true', and false otherwise.

I managed to figure this out on my own. I used the resolve.alias property in the Webpack configuration to allow a 'soft fail' when the file doesn't exist. I changed my import to use an alias (my-compiled-package-alias), which would conditionally resolve to either the built file or an empty dummy file (dev/import-dummy.js). I had to use resolve.alias rather than resolve.fallback, since Vue2 uses Webpack v4 which doesn't include the latter property.

My updated code:

if (process.env.VUE_APP_USE_COMPILED == 'true') {
    const compiledPackage = require('my-compiled-package-alias')
    Vue.use(compiledPackage)
}

In my vue.config.js:

module.exports = {
  ...
  configureWebpack: {
    resolve: {
      alias: {
        "my-compiled-package-alias":
          process.env.VUE_APP_USE_COMPILED ? "./dist/built.esm.js": "./import-dummy.js"
      }
    }
  },
  ...
}
Related