如何跨多个文件中的多个 Vue 实例正确使用 Vue 3 composition-api
Posted
技术标签:
【中文标题】如何跨多个文件中的多个 Vue 实例正确使用 Vue 3 composition-api【英文标题】:How to correctly use Vue 3 composition-api across multiple Vue instances in multiple files 【发布时间】:2021-02-06 23:01:40 【问题描述】:tl;dr 在基础 js 文件中导入 Vue3 的正确方法是什么,然后在将在该基础文件之后加载的其他独立 js 文件中使用 Vue 的 composition-api?
我正在使用 Vue 来增强特定页面的用户体验。例如,在注册页面以执行 ajax 请求并显示服务器错误而无需重新加载页面。简而言之,MPA 中的迷你 SPA...
在 Vue2 中,在基础文件中导入 Vue,然后实例化一个新的 Vue 实例并在后续文件中使用 Vue 的 options-api 没有问题。并且后续文件的大小保持最小,因为它们只包含该文件所需的逻辑。
但是,由于 Vue3 的 composition-api 需要导入 ref, reactive, watch, onMount...etc
,导致后面的文件重新导入 Vue。我试图克服这个问题如下:
// register.blade.php (contains)
<div id="root">
<input type="text" name="first_name" v-model="FirstName">
<input type="text" name="last_name" v-model="LastName">
// (before edit) <script src="main.js"></script>
// (before edit) <script src="register.js"></script>
<script src=" mix('/main.js') "></script>
<script src=" mix('/register.js') "></script>
</div>
// main.js (contains)
// (before edit) import Vue from 'node_modules/vue/dist/vue.js';
// (before edit) window.Vue = Vue;
window.Vue = require('vue');
// register.js (contains)
const app = Vue.createApp(
setup()
const FirstName = Vue.ref('');
const LastName = Vue.ref('');
const FullName = Vue.computed(() => FirstName.value + ' ' + LastName.value);
return
FirstName, LastName, FullName
);
app.mount('#root');
这对于这个简单的例子来说很好,但我想知道前缀 Vue.
的方法是否正确?是否可以使用该方法访问 Vue 为 setup() 方法公开的所有函数?
编辑: 我正在使用 laravel mix 包装的 webpack,为了简单起见,我从初始代码中删除了它,但我认为它被证明是相关的。对最初提供的代码中的编辑进行注释以避免混淆。
// webpack.mix.js (contains)
mix.webpackConfig(
resolve:
alias:
'vue$': path.resolve(__dirname, 'node_modules/vue/dist/vue.esm-bundler.js'),
);
mix.js('resources/main.js', 'public/main.js')
.js('resources/register.js', 'public/register.js')
.version();
【问题讨论】:
【参考方案1】:在每个.js
文件中从 Vue 3(ref
、watch
、computed
...)导入单独的部分时,应该没有额外的开销。事实上,如果您使用的是捆绑器,这将有助于摇树过程使生成的文件更小 (great explanation by Evan You)。
导入所有 Vue 并以当前方式使用它并没有错,类似于在 Vue 2 中的使用方式。如果语法困扰您,您可以解构您使用的内容,即
// register.js (contains)
const ref, computed = Vue;
const app = Vue.createApp(
setup()
const FirstName = ref('');
const LastName = ref('');
const FullName = computed(() => FirstName.value + ' ' + LastName.value);
return
FirstName, LastName, FullName
);
app.mount('#root');
编辑:
我对 Laravel Mix 不熟悉,但也许你可以试试这样:
// webpack.mix.js (contains)
const jsfiles = [
'resources/main.js',
'public/main.js',
'resources/register.js',
'public/register.js',
];
mix.js(...jsFiles).extract(['vue']).webpackConfig(
resolve:
alias:
'vue$': path.resolve(__dirname, 'node_modules/vue/dist/vue.esm-bundler.js'),
).version();
// now in your `register.js` and `main.js` use `import`, not `require`
//
// import Vue from 'vue';
【讨论】:
谢谢,这工作得很好。我更新了代码以更好地展示捆绑的处理方式。我想知道是否有更好的方法来尝试在main.js
中导入以获得正确的摇树,因为我想现在 Vue 是作为一个整体导入的。因此,如果我要跟踪main.js
之后的所有后续文件使用的所有功能,是否有更好的导入方法并且仍然能够使用不带前缀的语法?再次感谢const ref, computed = Vue;
我已经更新了我的答案。我想知道是不是因为使用了require
而不是import
。
提取确实生成了manifest.js
和vendor.js
,其中vendor.js
的大小反映了整个Vue 被导入。然后,当在任何其他文件中使用 import Vue from 'vue';
导入 Vue 时,最终会在该文件中再次导入 Vue。您的第一个答案对于最初的问题已经很完美了,至于关于摇树的后续问题,也许 Laravel Mix 本身需要修改以支持 Vue3 的正确摇树。再次感谢const ref, computed = Vue;
更新:当前版本的 Laravel Mix 5 仅支持 Vue2,Laravel Mix 6 的 beta version 支持 Vue3,tree shaking 工作正常。提取webpack.mix.js
中的供应商文件时要考虑的一个错误是,使用mix.extract(['vue'])
会导致在从vue 导入的所有文件中复制vue,而使用通配符mix.extract()
提取所有使用的node_modules 库时,会导致正确的摇树和vue在从 vue 导入的任何文件中都没有重复。【参考方案2】:
你可以使用Vue.ref
或ref
如果你像这样import ref,reactive from 'vue/dist/vue.js';
那样描述
这应该不是必需的:
window.Vue = Vue;
只要您在每个文件中使用import Vue from 'vue/dist/vue.js';
,例如register.js
(或解构版本)。即使您有多个导入,也不意味着它将被多次重新包含。打包器只会添加一次 Vue(或部分 Vue 库)。
【讨论】:
通过在register.js
中添加import ref, computed from 'vue';
并使用laravel mix 编译,文件大小从几千字节跃升至1.04 MiB。我认为这是因为 webpack 不知道 register.js
会在 main.js
之后出现,并且会继承 main.js
中已经导入的内容。如果我在编辑前的问题没有画出完整的画面,请接受我的道歉以上是关于如何跨多个文件中的多个 Vue 实例正确使用 Vue 3 composition-api的主要内容,如果未能解决你的问题,请参考以下文章
如何跨同一个 Web 应用程序的多个实例存储会话信息? [复制]