【问题标题】:How to correctly use Vue 3 composition-api across multiple Vue instances in multiple files如何跨多个文件中的多个 Vue 实例正确使用 Vue 3 composition-api
【发布时间】: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();

【问题讨论】:

    标签: javascript vue.js webpack vuejs3 vue-composition-api


    【解决方案1】:

    在每个.js 文件中从 Vue 3(refwatchcomputed...)导入单独的部分时,应该没有额外的开销。事实上,如果您使用的是捆绑器,这将有助于摇树过程使生成的文件更小 (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.jsvendor.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.refref 如果你像这样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 中已经导入的内容。如果我在编辑前的问题没有画出完整的画面,请接受我的道歉
    猜你喜欢
    • 2020-11-10
    • 1970-01-01
    • 1970-01-01
    • 2020-04-09
    • 2020-03-30
    • 2019-01-15
    • 1970-01-01
    • 2020-03-26
    • 2021-08-15
    相关资源
    最近更新 更多