首页 > 解决方案 > 将插件与 Rollup 捆绑在一起,但在客户端应用程序的包 (Nuxt) 中导入了重复的 Vue.js 包

问题描述

亲爱的 Stack Overflow / Vue.js / Rollup 社区

对于使用 Vue 和 Rollup 的主要插件开发人员来说,这可能是一个菜鸟问题。我会非常明确地写下这个问题,希望它可以在未来帮助像我这样的其他菜鸟。

我有一个简单的插件,可以帮助进行表单验证。这个插件中的一个组件导入了 Vue,以便以编程方式创建一个组件并在挂载时附加到 DOM,如下所示:

import Vue from 'vue'
import Notification from './Notification.vue' /* a very simple Vue component */
...
mounted() {
  const NotificationClass = Vue.extend(Notification)
  const notificationInstance = new NotificationClass({ propsData: { name: 'ABC' } })
  notificationInstance.$mount('#something')
}

这可以按预期工作,并且此插件使用 Rollup 捆绑,配置如下:

import vue from 'rollup-plugin-vue'
import babel from 'rollup-plugin-babel'
import { terser } from 'rollup-plugin-terser'
import resolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs'

export default {
  input: 'src/index.js',
  output: {
    name: 'forms',
    globals: {
      vue: 'Vue'
    }
  },
  plugins: [
    vue(),
    babel(),
    resolve(),
    commonjs(),
    terser()
  ],
  external: ['vue']
}

正如你所看到的,Vue.js 在这个包中被外部化了。目的(和假设)是导入此插件的客户端应用程序将在 Vue 上运行,因此无需在此处捆绑它(假设)。

捆绑器使用的非常简单的 src/index.js 如下:

import Form from './Form.vue'

export default {
  install(Vue, _) {
    Vue.component('bs-form', Form)
  }
}

Rollup 创建 2 个文件(一个 esm 和一个 umd)并在 plugins package.json 文件中引用它们,如下所示:

  "name": "bs-forms",
  "main": "./dist/umd.js",
  "module": "./dist/esm.js",
  "files": [
    "dist/*"
  ],
  "scripts": {
    "build": "npm run build:umd & npm run build:es",
    "build:es": "rollup --config rollup.config.js --format es --file dist/esm.js",
    "build:umd": "rollup --config rollup.config.js --format umd --file dist/umd.js"
  }

到目前为止,一切都按预期工作,并且捆绑包生成得很好。

客户端应用程序(Nuxt SSR)通过一个非常简单的插件文件导入来导入这个插件(使用 npm-link,因为它正在开发中):

/* main.js*/
import Vue from 'vue'

import bsForms from 'bs-forms'
Vue.use(bsForms)

此插件文件 (main.js) 作为插件添加到 nuxt.config.js:

// Nuxt Plugins
...
plugins: [{src: '~/plugins/main'}]
...

一切仍然按预期工作,但问题来了:

问题截图 由于客户端是 Nuxt 应用程序,因此默认情况下会导入 Vue,但也会在客户端中导入外部化的 Vue 模块(通过表单插件)。因此,客户端捆绑包中存在此包的副本。

我猜客户端应用程序可以配置其 webpack 配置以删除这个重复的模块。也许通过使用诸如 Dedupe 插件之类的东西?有人可以建议如何最好地处理这样的情况吗?

但我真正想学习的是,首先捆绑插件的最佳实践,这样客户端就不必更改其配置中的任何内容,只需导入此插件并继续前进。

我知道在插件中导入 Vue.js 一开始可能不是一件好事。但是像这样的导入也可能有其他原因,例如想象插件可以用 Typescript 和 Vue.js 编写/Typescript 是使用 Vue.extend 语句(见下文)编写的,它也导入 Vue(按顺序启用类型接口):

import Vue from 'vue'

const Component = Vue.extend({
  // type inference enabled
})

所以这是一个很长的问题。请汇总的大师们,通过建议最佳实践方法(或您的方法)来帮助我和社区来处理此类情况。

谢谢!!!!

标签: vue.jswebpackpluginsnuxt.jsrollup

解决方案


我遇到了同样的问题,我发现@vatson 的这个答案非常有帮助

您的问题是“npm 链接”、nodejs 模块加载的性质以及 vue 对来自不同地方的多个实例的不容忍性的组合。

简短介绍 nodejs 中的导入如何工作。如果您的脚本有某种库导入,那么 nodejs 最初会在本地 node_modules 文件夹中查找,如果本地 node_modules 不包含所需的依赖项,那么 nodejs 会转到上面的文件夹以查找 node_modules 和您在那里导入的依赖项。

你不需要在 NPM 上发布你的包。如果您使用本地生成包npm pack然后将其安装在您的其他项目中就足够了npm install /absolute_path_to_your_local_package/your_package_name.tgz。如果您更新包中的某些内容,您可以在其他项目中重新安装它,一切都应该正常。

npm pack这是关于和npm link https://stackoverflow.com/a/50689049/6072503之间区别的来源。


推荐阅读