在 CLI 构建中使用 CDN 组件? [英] Use CDN Components with a CLI Build?
问题描述
所以,到目前为止,我们一直在使用标准脚本标签为 Vue 构建我们的 Vue 应用程序(主要是为了我们可以慢慢地从 jQuery/Knockout-heavy 应用程序过渡),但随着我们开始转换我们更复杂的应用程序,如果我们不尽快切换到 CLI 构建,我已经可以看到我们将要推进的维护问题.
So, up until now, we've been building our Vue applications utilizing the standard script tag include for Vue (mostly so we can slowly transition from jQuery/Knockout-heavy apps), but as we start to convert our more complex apps, I can already see the maintenance issues we're going to have moving forward if we don't make the switch to the CLI build sooner than later.
现在,这对我们的许多应用程序来说都不是问题,但由于我们在 Vue 应用程序的早期采用了内部 CDN"方法,因此在 Webpack 中捆绑所有内容似乎在多功能性方面倒退了一步.现在我们提供 4 个文件,然后我们的 MVC 应用程序中的每个路由都有自己关联的 Vue 实例(即:about.js),它控制整个 UI 及其逻辑.我们的 CDN 服务于:1. polyfills.js(用于浏览器兼容性),2. vendor.js(axios,moment.js 和其他一些),3. vue.js(vue + vee-validate)和 4.components.js(我们自己的自定义 UI 组件库).
Now, this isn't an issue for many of our apps, but since we adopted an "internal CDN" approach early on in our Vue apps, bundling everything in Webpack seems like somewhat of a step back in versatility. Right now we serve 4 files and then each route within our MVC app has its own associated Vue instance (ie: about.js) which controls the entire UI and its logic. Our CDN serves: 1. polyfills.js (for browser compatibility), 2. vendor.js (axios, moment.js and a few others), 3. vue.js (vue + vee-validate) and 4. components.js (our own custom UI component library).
总的来说,我不关心 1-3.这些都可以捆绑在 webpack CLI 构建中.第 4 点是我挂断电话,因为通过 CDN 提供服务使我们能够立即将更新推送到我们所有的应用程序,而无需运行新版本.目前,我们只有 7 个应用程序运行完整的 Vue 构建,但我们的目的是最终将我们所有 80 多个内部应用程序以及几个现有和新的外部应用程序转换为 Vue.如果我们的 30 个应用程序正在使用我们的一个共享组件,并且需要对其进行更新以解决任何功能、可访问性等问题,这意味着我们必须重建所有 30 个应用程序并推送它们,这根本不理想.
In general, I don't care about 1-3. These can all be bundled in the webpack CLI build. It's #4 that I'm hung up on, as serving over the CDN has allowed us to push updates to all of our apps instantaneously, without running a new build. Right now, we only have 7 apps running a full Vue build, but our intention is to eventually convert all 80+ of our internal applications, plus several existing and new external applications over to Vue. If 30 of our apps are using one of our shared components and it needs to be updated to address any functional, accessibility, etc. concerns, that means we have to rebuild all 30 apps and push them, which isn't ideal at all.
有没有办法继续只为我们的组件使用 CDN 构建,并将其余部分作为 SPA 与 Webpack 捆绑在一起?
Is there a way to continue to use the CDN build just for our components and bundle the rest as a SPA with Webpack?
请注意:这与引用外部 JS 库(如 jQuery)不同.我正在尝试添加 Vue 组件.如果您从外部加载这样的库,然后尝试通过以下方式导入组件:
Please note: This is not the same as referencing an external JS library, like jQuery. I'm trying to add Vue Components. If you load a library like this externally and then try to import the component via:
<ComponentName/>
Vue 会给你一个控制台错误说:
Vue will give you a console error saying:
[Vue warn]: Unknown custom element: <ComponentName> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
---> <App> at srcApp.vue
<Root>
简单地添加如下:
export default {
name: 'app',
components: {
ComponentName
}
}
将返回:
Uncaught ReferenceError: ComponentName is not defined
因为没有导入.但是尝试导入它也不起作用,因为它不存在于应用程序中,它是外部的.
Because there's no import. But trying to import it also won't work, because it doesn't exist in the app, it's external.
推荐答案
您希望使用 Vue webpack CLI 构建来管理您的应用程序,但保持具有独立 Vue 组件的灵活性,即服务作为多个应用程序/项目共有的单独文件.这是您用内部 CDN"描述的架构.
You would like to manage your apps with a Vue webpack CLI build, but keeping the flexibility of having independent Vue components, i.e. served as separate files that are common to several apps / projects. That is an architecture that you describe with an "internal CDN".
正如@RandyCasburn 指出,您可以通过简单地全局公开 Vue
(通常从 CDN 将其加载到 中)然后加载使用
Vue 的独立文件来实现上述目标.组件
全局注册你的组件.
As pointed out by @RandyCasburn, you could achieve the above objective by simply exposing Vue
globally (typically loading it in a <script>
from a CDN) and then loading your independent files that use Vue.component
to register your components globally.
参考:如何将 Vuejs 组件导入"到 index.html?
但是,您希望能够将这些独立的 Vue 组件开发为单文件组件 (SFC).
However, you would like to be able to develop these independent Vue Components as Single File Components (SFC).
对于您描述的用法,我基本上看到了 2 个有趣的解决方案:
I see basically 2 interesting solutions for the usage you describe:
- 填补了创建小型构建步骤工具的空白,将您的 SFC 转换为纯 JS 文件,该文件可以通过
<script>
标签加载,并使用Vue.component
. - 与其构建通过
Vue.component
注册的 JS 文件,不如让它公开 Vue 组件配置/options 对象,以便它可以是 本地注册 和 异步加载.这需要更多的工作,因为您需要设置每个消费者应用 webpack 配置以异步加载非捆绑块.
- Filling the gap of creating the small build step tool to convert your SFC into a plain JS file, that can be loaded through a
<script>
tag and that registers the component globally withVue.component
. - Instead of building a JS file that registers through
Vue.component
, make it expose the Vue Component configuration / options object, so that it can be locally registered and loaded asynchronously. This requires more work because you need to setup each consumer app webpack config to asynchronously load non-bundled chunks.
选项 1:使用 Vue.component
实际上最近有一个模板项目提供了这个功能:
There is actually a recent template project that offers this feature:
https://github.com/RonnieSan/vue-browser-sfc
用于将单个文件组件 (.vue) 编译为独立 JS 文件以在浏览器中使用的构建设置模板
Template for build setup to compile Single File Components (.vue) into a standalone JS file for use in the browser
它使用 webpack 将您的 .vue
文件转换为编译后的 JS 文件,该文件使用 Vue.component
全局注册组件.
It uses webpack to convert your .vue
file into a compiled JS file that registers the component globally with Vue.component
.
如果您对精简代码感兴趣,您也可以使用 Rollup 而不是 webpack 来执行非常相似的过程.使用 rollup-plugin-vue.
You could also do a very similar process using Rollup instead of webpack, if leaner code is of interest to you. Use rollup-plugin-vue.
这种方式的优点是简单易懂,你只需要重构你的HTML来加载Vue,然后是你所有常用组件的JS文件.即使在开发过程中,这些组件也应该是全局可用的,因此 Vue 运行时不应该抱怨Unknown custom element",并且在您的消费者应用程序中,只需不要 import
/declare
The advantage of this approach is that it is easy to understand, you just need to refactor your HTML to load Vue, then all your common components JS files. Even during development, these components should be globally available, so Vue runtime should not complain about "Unknown custom element", and in your consumer app, just do not import
/ declare them.
缺点是您必须事先加载所有这些组件,无论您是否使用它们.
The drawback is that you have to load all these components before hand, whether you use them or not.
选项 2:将 Vue SFC 转换为单个 JS 文件作为异步"选项对象
这个更有趣,但设置起来更复杂.
This one is far more interesting, but more complicated to set up right.
与之前的解决方案一样,在组件端,您使用构建步骤来转换 SFC .vue
文件,但不需要额外的带有 Vue.component的包装器代码>声明.只需让 webpack 或 Rollup 将组件选项对象包装在 IIFE 或 UMD 中,以便在全局上下文中注册该对象.
Like the previous solution, on the component side, you use a build step to convert the SFC .vue
file, but you do not need an extra wrapper with Vue.component
declaration. Just have webpack or Rollup wrap the component options object in an IIFE or UMD that registers the object in the global context.
例如你的 rollup.config.js
文件看起来像:
For example your rollup.config.js
file would look like:
import VuePlugin from 'rollup-plugin-vue'
export default {
input: 'components/my-component.vue',
output: {
file: 'dist/my-component.js',
name: 'MyComponent', // <= store the component on `window.MyComponent`
format: 'umd',
},
plugins: [VuePlugin()]
}
然后在您的消费者应用程序上,您仍然import()
并声明您的组件,但您需要设置 webpack 配置,以便它不会捆绑应用程序中的文件,而是从网络.例如:
Then on your consumer apps, you still import()
and declare your components, but you need to setup the webpack configuration so it does not bundle the files in the app, but asynchronously loads them from the network. For example:
components: {
'my-component': () => import('my-component'),
},
为此,您可以使用 dynamic-cdn-webpack-plugin,但你必须提供你自己的resolver
函数,因为默认module-to-cdn
使用自己的模块列表可配置.
For that you can use dynamic-cdn-webpack-plugin, but you have to provide your own resolver
function, because the default module-to-cdn
uses its own modules list that is not configurable.
您在 dynamic-cdn-webpack-plugin 的 中列出您的组件仅
数组选项,提供一个resolver
mimics module-to-cdn
但使用您自己的列表.例如:
You list your components in dynamic-cdn-webpack-plugin's only
array option, provide a resolver
that mimics module-to-cdn
but uses your own list. For example:
const modules = {
'my-component': {
var: 'MyComponent', // <= name under which the component will be stored.
versions: {
'*': {
development: 'http://localhost:8080/my-cdn/my-component.js',
production : 'http://localhost:8080/my-cdn/my-component.min.js',
},
},
},
};
要使此方案起作用,您还必须在 package.json
依赖项中将组件列为模块,可能带有一个虚拟的 本地路径 作为版本规范,以确保您不会尝试从 npm 注册表加载它们.
For this scheme to work, you also have to list your components as modules in your package.json
dependencies, possibly with a dummy local path as version spec, to make sure you do not try to load them from npm registry.
优点是您不必接触 HTML 文件,异步加载由您的应用直接管理.您可以捆绑 Vue 并且不关心加载顺序/顺序.CDN 组件在实际需要时按需加载.
The advantage is that you do not have to touch your HTML files, the async loading is directly managed by your apps. You can bundle Vue and do not care about the loading order / sequence. CDN components are loaded on demand when actually needed.
缺点是它需要为所有消费者应用程序进行更复杂的 webpack 配置,但它是完全可以管理的.
The drawback is that it requires a more complex webpack config for all your consumer apps, but it is totally manageable.
这篇关于在 CLI 构建中使用 CDN 组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!