使用 Rollup 捆绑插件,但在客户端应用程序的捆绑包中导入重复的 Vue.js 包 (Nuxt)

Kem*_*aya 3 plugins rollup webpack vue.js nuxt.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')
}
Run Code Online (Sandbox Code Playgroud)

这按预期工作,并且该插件使用 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']
}
Run Code Online (Sandbox Code Playgroud)

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

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

import Form from './Form.vue'

export default {
  install(Vue, _) {
    Vue.component('bs-form', Form)
  }
}
Run Code Online (Sandbox Code Playgroud)

Rollup 创建 2 个文件(一个 esm 和一个 umd)并在插件 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"
  }
Run Code Online (Sandbox Code Playgroud)

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

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

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

import bsForms from 'bs-forms'
Vue.use(bsForms)
Run Code Online (Sandbox Code Playgroud)

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

// Nuxt Plugins
...
plugins: [{src: '~/plugins/main'}]
...
Run Code Online (Sandbox Code Playgroud)

一切仍然按预期进行,但问题来了:

问题截图 由于客户端是 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
})
Run Code Online (Sandbox Code Playgroud)

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

谢谢你!!!!

小智 5

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

您的问题是“npm link”、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 /sf/answers/3548233461/之间差异的来源。