vue.runtime.esm-browser.js无法渲染Vue 3组件。

11

我使用Vue cli创建了一个Vue 3项目。我正在使用webpack配置来管理我的构建过程。当我将我的Vue捆绑包指向vue.runtime.esm-browser.js时,浏览器控制台会出现警告。"[Vue warn]: 组件提供的模板选项但是在此版本的Vue中不支持运行时编译。请使用"vue.esm-browser.js"。"

检查文档后发现,"vue-loader"插件将HTML模板转换为渲染函数。看起来我缺少一些必要的Webpack配置。

入口文件:main.js

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

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

Webpack配置文件

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"
      }
    } 
  };
};

核心组件A.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",
    },
  ],
};

如何在HTML文件中使用我的组件

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

该组件未在浏览器中渲染。取而代之的是下面显示的消息。

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>

我也遇到了同样的问题。 - Ravi Meganathan
3个回答

14
如果您正在使用Vite,将别名'vue': 'vue/dist/vue.esm-bundler'添加到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',
    },
  }
})

13

vue-loader将HTML模板转换为渲染函数,但仅在SFC(单文件组件)- .vue文件中进行转换(可以从Webpack配置中的Vue规则中看出),并且仅转换提供在SFC的<template></template>块中的模板。

但是您的HTML文件中有一个模板 - <div id="app">的内容本质上是Vue模板。Runtime + Compiler vs. Runtime-only

文档 vue.esm-bundler.js:包括运行时编译器。如果您使用打包程序但仍想要运行时模板编译(例如DOM内模板或通过内联JavaScript字符串的模板 - 组件template选项),请使用此选项。

如果您使用Webpack,还应使用“bundler”版本的Vue。

Webpack.config.js

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

...你不需要切换缩小版或开发版的捆绑包,因为Webpack会(在正确配置的情况下)像优化您自己的代码一样优化Vue代码。

此外,注意文档中的这句话:使用process.env.NODE_ENV保护离开prod/dev分支(必须由打包工具替换)

NODE_ENV通常用于定义环境类型,并被Vue用于决定要包含哪些代码...

注意

我真的不明白为什么对于使用Vue CLI创建的项目,您还要使用自己的Webpack配置,因为Vue CLI的整个目的是为您管理Webpack配置并提供大量选项来自定义它...没有任何意义。


1
谢谢。这确实帮助我解决了我的问题。 - Saju Thankathurai
如果我将alias: { vue:"@vue/runtime-dom" }作为别名添加,那么就会发生树摇。但是,如果我将别名添加为alias: { vue:"vue/dist/vue.esm-browser.prod.js", },那么就不会发生树摇。如果我使用vue-esm-browser.prod.js,有没有一种方法可以进行树摇呢? - Saju Thankathurai
没有 browser 构建的依赖项与 global 构建相同(请参见我的答案中的文档链接)。您为什么要在 Webpack 中使用 browser 构建,而文档告诉您要使用 bundler 版本? - Michal Levý
bundler 版本会将 @babel/parser/lib 添加到我的 vendor-bundle 中,导致文件非常大。 - Saju Thankathurai
这真的很奇怪。也许与文档中的这个句子有关:Leaves prod/dev branches with process.env.NODE_ENV guards (must be replaced by bundler)。你是否尝试使用(类似)标准的 NODE_ENV='production' 环境变量而不是你自己的变量? - Michal Levý

4

你只需更改 Webpack.config.js 文件即可。

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

随着

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

这对我有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接