vue.runtime.esm-browser.js 不渲染 Vue 3 组件

Posted

技术标签:

【中文标题】vue.runtime.esm-browser.js 不渲染 Vue 3 组件【英文标题】:vue.runtime.esm-browser.js does not render Vue 3 components 【发布时间】:2021-02-03 23:55:56 【问题描述】:

我使用 Vue cli 创建了一个 vue 3 项目。我正在使用 webpack 配置来管理我的构建。当我将我的 vue 包指向 vue.runtime.esm-browser.js 时,我会在浏览器控制台中收到警告。 “[Vue 警告]:组件提供的模板选项,但此 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.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",
    ,
  ],
;

在 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>

【问题讨论】:

我也面临同样的问题 【参考方案1】:

vue-loader 仅在 SFC(单一文件组件)-.vue 文件中将 html 模板转换为呈现函数(从 Webpack 配置中的 vue 规则可以看出)-和 仅在&lt;template&gt;&lt;/template&gt; SFC 块中提供的模板

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

Docs vue.esm-bundler.js:包括运行时编译器。如果您正在使用捆绑器但仍需要运行时模板编译(例如,DOM 内模板或通过内联 javascript 字符串的模板 - 组件 template 选项),请使用此选项。

另外,如果你使用 Webpack,你应该使用“捆绑器”版本的 Vue

Webpack.config.js

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

...您不需要切换 minified/dev 包,因为 Webpack 将(在正确配置时)以与您自己的代码相同的方式优化 Vue 代码..

另外,请注意文档中的这句话:process.env.NODE_ENV 守卫离开 prod/dev 分支(必须用 bundler 替换)

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

注意

我真的不明白,当 Vue CLI 的全部目的是为你管理 webpack 配置并为 customize it... 提供大量选项时,我真的不明白你为什么要为使用 Vue CLI 创建的项目使用自己的 Webpack 配置。没有任何意义

【讨论】:

谢谢。这确实有助于解决我的问题。 如果我添加 alias: vue:"@vue/runtime-dom" 作为别名,就会发生摇树。但是如果我将别名添加为alias: vue:"vue/dist/vue.esm-browser.prod.js", ,则不会发生摇树。如果我使用 vue-esm-browser.prod.js,有没有办法摇树? 没有。 browser build 具有与 global build 相同的所有依赖项内联(请参阅我的答案中的文档链接)。当文档告诉您使用bundler 版本时,您为什么要使用browser 与Webpack 一起构建? 捆绑器版本将@babel/parser/lib 添加到我的供应商捆绑包中,它的大小非常重。 这真的很奇怪。也许它与文档中的这句话有关:Leaves prod/dev branches with process.env.NODE_ENV guards (must be replaced by bundler)。您是否尝试使用(某种)标准 NODE_ENV='production' ENV 变量而不是您自己的?

以上是关于vue.runtime.esm-browser.js 不渲染 Vue 3 组件的主要内容,如果未能解决你的问题,请参考以下文章