12

I created a vue 3 project using Vue cli. I am using a webpack config to manage my build. When I point my vue bundle to vue.runtime.esm-browser.js, then I get a warning in browser console. "[Vue warn]: Component provided template option but runtime compilation is not supported in this build of Vue. Use "vue.esm-browser.js" instead."

When I checked the docs, it was mentioned as "vue-loader" plugin converts the html template to render functions. Looks like I am missing something which is needed to webpack.

Entry file : main.js

import { createApp } from "vue";
import corecomponentA from "../core/components/corecomponentA.vue";

createApp({
  components: {
    "core-component-a": corecomponentA,
  },
}).mount("#app");

Webpack.config.js

var path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const { VueLoaderPlugin } = require("vue-loader");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;
const WebpackBar = require("webpackbar");

module.exports = (env, options) => {
  const devMode = options.mode != "production";
  return {
    entry: {
      "vue-bundle-store": "./src/entry/main.js",
    },
    output: {
      path: path.resolve(
        __dirname,
        "./../ui.clientlibs/src/js/"
      ),
      filename: "[name].js",
      chunkFilename: "[name].js",
      publicPath: process.env.BASE_URL,
    },

    module: {
      rules: [
        {
          enforce: "pre",
          test: /\.js$/,
          exclude: /node_modules/,
          loader: "eslint-loader",
        },
        {
          test: /\.vue$/,
          loader: "vue-loader",
        },
        {
          test: /\.js$/,
          loader: "babel-loader",
          exclude: "/node_modules/",
          query: {
            presets: ["@babel/preset-env"],
          },
        },
        {
          test: /\.ts$/,
          exclude: /node_modules/,
          use: [
            {
              loader: "babel-loader",
              options: { babelrc: true },
            },
            {
              loader: "ts-loader",
              options: { appendTsSuffixTo: [/\.vue$/] },
            },
          ],
        },
      ],
    },
    stats: {
      colors: true,
    },
    optimization: {
      splitChunks: {
        cacheGroups: {
          commons: {
            test: /[\\/]node_modules[\\/]/,
            name: "vendor-bundle",
            chunks: "all",
          },
        },
      },
      minimizer: !devMode
        ? [
            new UglifyJsPlugin({
              sourceMap: false,
              uglifyOptions: {
                chunkFilter: (chunk) => {
                  if (chunk.name === "vendor-bundle") {
                    return false;
                  }

                  return true;
                },
                compress: {
                  drop_console: true,
                },
                mangle: {
                  reserved: ["vueIns", "args", "el"],
                },
              },
            }),
          ]
        : [],
    },
    devtool: "source-map",    
    plugins: [      
      new CleanWebpackPlugin(),
      new VueLoaderPlugin(),
      new WebpackBar(),
      new BundleAnalyzerPlugin({
        analyzerPort: 4000,
        openAnalyzer: false,
        analyzerMode: "static",
      }),
    ] ,
    resolve: {
      extensions: [".ts", ".js", ".vue", ".json"],
      alias: {                
       vue: devMode ? "vue/dist/vue.runtime.esm-browser.js" : "vue/dist/vue.runtime.esm-browser.prod.js"
      }
    } 
  };
};

coreComponentA.vue

<script lang="ts">
import { h, ref, reactive } from "vue";

export default {
  setup() {
    const str = ref("Core component B");
    const object = reactive({ foo: "bar" });
    return () => h("div", [str.value, object.foo]);
  }
};
</script>

package.json

{
  "name": "vue3.test",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "test:unit": "vue-cli-service test:unit",
    "lint": "vue-cli-service lint",
    "analyze-bundle": "webpack-bundle-analyzer stats.json",
    "bundle": "webpack --mode=production --env.production --config webpack.config.js",
    "bundle-dev": "webpack --mode=development --env.production=false --config webpack.config.js",
    "stats": "webpack --mode=production --env.production --config webpack.config.js --profile --json > stats.json"
  },
  "dependencies": {
    "vue": "^3.0.2"
  },
  "devDependencies": {
    "@types/jest": "^24.0.19",
    "@typescript-eslint/eslint-plugin": "^2.33.0",
    "@typescript-eslint/parser": "^2.33.0",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-typescript": "~4.5.0",
    "@vue/cli-plugin-unit-jest": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.2",
    "@vue/eslint-config-prettier": "^6.0.0",
    "@vue/eslint-config-typescript": "^5.0.2",
    "@vue/test-utils": "^2.0.0-0",
    "clean-webpack-plugin": "^3.0.0",
    "core-js": "^3.6.5",
    "eslint": "^6.7.2",
    "eslint-plugin-prettier": "^3.1.3",
    "eslint-plugin-vue": "^7.0.0-0",
    "html-webpack-plugin": "^3.2.0",
    "prettier": "^1.19.1",
    "typescript": "~3.9.3",
    "uglifyjs-webpack-plugin": "^2.2.0",
    "vue-jest": "^5.0.0-0",
    "vue-loader": "^16.0.0-beta.8",
    "webpack-cli": "^3.3.10",
    "webpackbar": "^4.0.0"
  }
}

babel.config.js

module.exports = {
  ignore: [/\/core-js/],
  presets: [
    [
      "@babel/preset-env",
      { modules: false, useBuiltIns: "usage", corejs: "3.6.5" },
    ],
  ],
  overrides: [
    {
      test: "./node_modules",
      sourceType: "unambiguous",
    },
  ],
};

Usage of my component in a html file

<div id="app">
<core-component-a></core-component-a>
</div>

The component is not rendered in browser. Instead the below message is displayed.

VM211871:1 [Vue warn]: Component provided template option but runtime compilation is not supported in this build of Vue. Use "vue.esm-browser.js" instead. 
  at <App>
1
  • I am also facing the same problem Commented Oct 21, 2020 at 5:50

3 Answers 3

20

If you are using Vite, add the alias 'vue': 'vue/dist/vue.esm-bundler' to vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      'vue': 'vue/dist/vue.esm-bundler',
    },
  }
})
Sign up to request clarification or add additional context in comments.

Comments

14

vue-loader converts the html template to render function only in SFC's (Sinle File Components) - .vue files (as you can tell from vue rule in Webpack config) - and only templates provided in <template></template> block of SFC

But you have a template in your HTML file - content of <div id="app"> is essentially Vue template. Runtime + Compiler vs. Runtime-only

Docs vue.esm-bundler.js: includes the runtime compiler. Use this if you are using a bundler but still want runtime template compilation (e.g. in-DOM templates or templates via inline JavaScript strings - component template option).

Also if you using Webpack, you should use "bundler" version of Vue

Webpack.config.js

alias: {                
       vue: "vue/dist/vue.esm-bundler.js"
}

...you don't need to switch minified/dev bundle because Webpack will (when configured correctly) optimize Vue code same way as your own code..

Also, pay attention to this sentence in the docs: Leaves prod/dev branches with process.env.NODE_ENV guards (must be replaced by bundler)

NODE_ENV is conventionally used to define the environment type and is used by Vue to decide what code to include...

Note

I don't really understand why are You using your own Webpack config for project created with Vue CLI when whole point of Vue CLI is to manage webpack config for you and offers plenty of options to customize it...doesn't make any sense

5 Comments

Thanks. This really helped to fix my issue.
If I add alias: { vue:"@vue/runtime-dom" } as alias, tree-shaking is happening. But If I add alias as alias: { vue:"vue/dist/vue.esm-browser.prod.js", }, then tree-shaking is not happening. Is there a way to tree-shake if I use vue-esm-browser.prod.js?
No. browser build has all dependencies inlined same as global build (see doc link in my answer). Any reason why do you want to use browser build with Webpack when docs are telling you to use bundler version ?
bundler version adds @babel/parser/lib to my vendor-bundle which is very heavy in size.
That's really strange. Maybe its related to this sentence in the docs: Leaves prod/dev branches with process.env.NODE_ENV guards (must be replaced by bundler). Did you try to use (sort of) standard NODE_ENV='production' ENV variable instead your own ?
4

you just have to replace on Webpack.config.js

alias: {                
       vue: devMode ? "vue/dist/vue.runtime.esm-browser.js" : "vue/dist/vue.runtime.esm-browser.prod.js"
}

With

vue: "vue/dist/vue.esm-bundler.js"

This works for me.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.