Vue单文件组件在静态HTML页面无法渲染且控制台报Vue未定义问题
你遇到的问题核心是:vue-loader仅负责编译*.vue单文件内部的<template>模板,你写在静态HTML文件#app节点内的内容、自定义组件标签,属于根Vue实例的运行时模板,这部分内容构建阶段vue-loader完全无法触及,必须依赖Vue的编译器才能在运行时解析为渲染函数,仅运行时版本的Vue没有编译器,自然无法渲染,才会出现你看到的函数注释占位符。
Vue官方文档说的不需要编译器的前提是:所有模板都在*.vue文件内完成预编译,根实例直接用render函数挂载根组件,不需要从DOM读取模板。你现在的用法是根实例直接挂载到#app,且模板存在于DOM中,不符合这个前提,所以必须引入编译器。
方案1:保留现有HTML写法,优化引入配置
如果你坚持要把静态内容和组件标签直接写在静态HTML的#app内,只需在webpack中配置Vue别名即可,不需要每次手动引入全路径的带编译器版本:
- 修改webpack.config.js,新增resolve配置:
module.exports = { // 原有配置不变 resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' } } }
修改后你直接import Vue from 'vue'就会自动引入带编译器的版本,不需要改业务代码。
2. 如果需要在控制台访问Vue,在page1_main.js最后加一行window.Vue = Vue即可,webpack默认会把模块封装在闭包内,不会暴露到全局作用域,所以你之前直接输Vue会提示未定义。
方案2:完全使用运行时版本,缩小产物体积
如果追求最小产物体积,不想引入30KB左右的编译器,需要调整根实例的挂载逻辑,放弃在HTML内写组件标签的写法:
你可以给每个要插入组件的位置单独设置挂载节点,比如把HTML里的<component1></component1>换成<div id="component1-mount"></div>,然后在page1_main.js里直接把组件挂载到对应节点:
import Vue from 'vue' import Component1 from './components/Component1.vue' new Vue({ render: h => h(Component1) }).$mount('#component1-mount')
这种写法所有组件的模板都在*.vue内预编译完成,不需要编译器,产物体积最小,也能满足你在静态HTML任意位置插入Vue组件的需求,不需要改整体页面结构,也不需要用Vue Router或者整站SPA。
你现在的splitChunks配置已经能把Vue和通用依赖抽离到vendor chunk,多页面共用的话不会重复打包,符合你的需求。如果要进一步缩小体积,可以在webpack production模式下开启tree shaking、关闭productionSourceMap即可。
内容的提问来源于stack exchange,提问作者Martin

