@esmx/rspack-vue 3.0.0-rc.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # @esmx/rspack-vue
2
+
3
+ 为 Vue 框架提供专业的构建支持,包含完整的 Vue 组件开发、构建与服务端渲染能力。
4
+
5
+ ## 特性
6
+
7
+ - 🚀 **高性能构建** - 基于 Rspack 的高性能构建,为 Vue 应用提供极致开发体验
8
+ - 💡 **框架集成** - 完整支持 Vue 2/3,内置 vue-loader 及相关优化配置
9
+ - 🎨 **组件支持** - 智能处理 .vue 单文件组件,支持模板、样式和脚本
10
+ - 🛠️ **SSR 支持** - 内置服务端渲染支持,轻松构建同构应用
11
+ - 🔧 **开发体验** - 支持热更新、智能提示和 TypeScript
12
+
13
+ ## 安装
14
+
15
+ ```bash
16
+ pnpm add @esmx/rspack-vue -D
17
+ # 或
18
+ yarn add @esmx/rspack-vue -D
19
+ # 或
20
+ npm install @esmx/rspack-vue -D
21
+ ```
22
+
23
+ ## 文档
24
+
25
+ 访问 [@esmx/rspack-vue 官方文档](https://www.esmnext.com/api/app/rspack-vue.html) 获取详细的使用指南和 API 文档。
26
+
27
+ ## 许可证
28
+
29
+ MIT
@@ -0,0 +1,2 @@
1
+ export * from '@esmx/rspack';
2
+ export * from './vue';
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ export * from "@esmx/rspack";
2
+ export * from "./vue.mjs";
@@ -0,0 +1,5 @@
1
+ import type { Esmx } from '@esmx/core';
2
+ import type { RspackVueAppOptions } from './vue';
3
+ type VueType = '2' | '3';
4
+ export declare function createRspackVueApp(esmx: Esmx, vueType: VueType, options?: RspackVueAppOptions): Promise<import("@esmx/core").App>;
5
+ export {};
@@ -0,0 +1,91 @@
1
+ import { createRspackHtmlApp, rspack } from "@esmx/rspack";
2
+ import { VueLoaderPlugin as VueLoader2Plugin } from "vue2-loader";
3
+ import { VueLoaderPlugin as VueLoader3Plugin } from "vue3-loader";
4
+ import { vue2Loader } from "./vue2-loader.mjs";
5
+ import { vue3Loader } from "./vue3-loader.mjs";
6
+ export function createRspackVueApp(esmx, vueType, options) {
7
+ return createRspackHtmlApp(esmx, {
8
+ ...options,
9
+ loaders: {
10
+ styleLoader: new URL(import.meta.resolve("vue-style-loader")).pathname,
11
+ ...options?.loaders
12
+ },
13
+ config(context) {
14
+ const { config, buildTarget } = context;
15
+ config.resolve = {
16
+ ...config.resolve,
17
+ extensions: [...config.resolve?.extensions ?? [], ".vue"]
18
+ };
19
+ config.plugins = config.plugins || [];
20
+ switch (vueType) {
21
+ case "2":
22
+ config.plugins.push(new VueLoader2Plugin());
23
+ break;
24
+ case "3":
25
+ config.plugins.push(new VueLoader3Plugin());
26
+ break;
27
+ }
28
+ if (buildTarget === "client") {
29
+ config.plugins.push(
30
+ new rspack.DefinePlugin({
31
+ "process.env.VUE_ENV": JSON.stringify(buildTarget)
32
+ })
33
+ );
34
+ }
35
+ const vueRuleUse = [
36
+ {
37
+ loader: new URL(import.meta.resolve(`vue${vueType}-loader`)).pathname,
38
+ options: {
39
+ ...options?.vueLoader,
40
+ experimentalInlineMatchResource: true,
41
+ optimizeSSR: buildTarget === "server"
42
+ }
43
+ }
44
+ ];
45
+ switch (vueType) {
46
+ case "2":
47
+ vueRuleUse.unshift(vue2Loader);
48
+ break;
49
+ case "3":
50
+ vueRuleUse.unshift(vue3Loader);
51
+ break;
52
+ }
53
+ config.module = {
54
+ ...config.module,
55
+ rules: [
56
+ ...config.module?.rules ?? [],
57
+ {
58
+ test: /\.vue$/,
59
+ use: vueRuleUse
60
+ }
61
+ ]
62
+ };
63
+ let vueAlias = null;
64
+ switch (vueType) {
65
+ case "2":
66
+ vueAlias = "vue/dist/vue.esm.js";
67
+ break;
68
+ case "3":
69
+ vueAlias = "vue/dist/vue.runtime.esm-browser.js";
70
+ break;
71
+ }
72
+ if (vueAlias) {
73
+ config.resolve.alias = {
74
+ ...config.resolve.alias,
75
+ vue$: vueAlias
76
+ };
77
+ }
78
+ if (vueType === "2") {
79
+ config.ignoreWarnings = [
80
+ ...config.ignoreWarnings ?? [],
81
+ (warning) => {
82
+ return warning.moduleDescriptor.name.includes(
83
+ "vue-server-renderer"
84
+ );
85
+ }
86
+ ];
87
+ }
88
+ options?.config?.(context);
89
+ }
90
+ });
91
+ }
package/dist/vue.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ import type { Esmx } from '@esmx/core';
2
+ import type { RspackHtmlAppOptions } from '@esmx/rspack';
3
+ export interface RspackVueAppOptions extends RspackHtmlAppOptions {
4
+ /**
5
+ * vue-loader 配置项
6
+ *
7
+ * 用于配置 Vue 单文件组件的编译选项,完整选项参考:
8
+ * https://github.com/vuejs/vue-loader
9
+ */
10
+ vueLoader?: Record<string, any>;
11
+ }
12
+ /**
13
+ * 创建 Vue 2 应用构建器
14
+ *
15
+ * @param esmx - Esmx 实例
16
+ * @param options - Rspack Vue 应用配置项
17
+ * @returns 返回一个 Promise,解析为构建好的应用实例
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import type { EsmxOptions } from '@esmx/core';
22
+ *
23
+ * export default {
24
+ * async devApp(esmx) {
25
+ * return import('@esmx/rspack-vue').then((m) =>
26
+ * m.createRspackVue2App(esmx, {
27
+ * config({ config }) {
28
+ * // 自定义 Rspack 配置
29
+ * }
30
+ * })
31
+ * );
32
+ * }
33
+ * } satisfies EsmxOptions;
34
+ * ```
35
+ */
36
+ export declare function createRspackVue2App(esmx: Esmx, options?: RspackVueAppOptions): Promise<import("@esmx/core").App>;
37
+ /**
38
+ * 创建 Vue 3 应用构建器
39
+ *
40
+ * @param esmx - Esmx 实例
41
+ * @param options - Rspack Vue 应用配置项
42
+ * @returns 返回一个 Promise,解析为构建好的应用实例
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * import type { EsmxOptions } from '@esmx/core';
47
+ *
48
+ * export default {
49
+ * async devApp(esmx) {
50
+ * return import('@esmx/rspack-vue').then((m) =>
51
+ * m.createRspackVue3App(esmx, {
52
+ * config({ config }) {
53
+ * // 自定义 Rspack 配置
54
+ * }
55
+ * })
56
+ * );
57
+ * }
58
+ * } satisfies EsmxOptions;
59
+ * ```
60
+ */
61
+ export declare function createRspackVue3App(esmx: Esmx, options?: RspackVueAppOptions): Promise<import("@esmx/core").App>;
package/dist/vue.mjs ADDED
@@ -0,0 +1,7 @@
1
+ import { createRspackVueApp } from "./vue-core.mjs";
2
+ export function createRspackVue2App(esmx, options) {
3
+ return createRspackVueApp(esmx, "2", options);
4
+ }
5
+ export function createRspackVue3App(esmx, options) {
6
+ return createRspackVueApp(esmx, "3", options);
7
+ }
@@ -0,0 +1,3 @@
1
+ import type { rspack } from '@esmx/rspack';
2
+ export default function (this: rspack.LoaderContext, text: string): string;
3
+ export declare const vue2Loader: string;
@@ -0,0 +1,22 @@
1
+ const FIX_ESM = `api.install(require('vue').default)`;
2
+ const ADD_IMPORT = `
3
+ function initImport () {
4
+ const mixins = Array.isArray(component.options.mixins) ? component.options.mixins : [];
5
+ mixins.push({
6
+ serverPrefetch () {
7
+ this.$ssrContext?.importMetaSet?.add(import.meta);
8
+ }
9
+ });
10
+ component.options.mixins = mixins;
11
+ }
12
+ initImport();
13
+ export default component.exports
14
+ `;
15
+ export default function(text) {
16
+ text = text.replaceAll(`api.install(require('vue'))`, FIX_ESM);
17
+ if (typeof this.target === "string" && this.target.includes("node")) {
18
+ text = text.replaceAll("export default component.exports", ADD_IMPORT);
19
+ }
20
+ return text;
21
+ }
22
+ export const vue2Loader = new URL(import.meta.resolve(import.meta.url)).pathname;
@@ -0,0 +1,3 @@
1
+ import type { rspack } from '@esmx/rspack';
2
+ export default function (this: rspack.LoaderContext, text: string): string;
3
+ export declare const vue3Loader: string;
@@ -0,0 +1,19 @@
1
+ const ADD_IMPORT = `
2
+ import { useSSRContext } from 'vue';
3
+ function initImport () {
4
+
5
+ const mixins = Array.isArray(__exports__.mixins) ? __exports__.mixins : [];
6
+ mixins.push({
7
+ created () {
8
+ const ctx = useSSRContext();
9
+ ctx?.importMetaSet?.add(import.meta);
10
+ }
11
+ });
12
+ __exports__.mixins = mixins;
13
+ }
14
+ initImport();
15
+ `;
16
+ export default function(text) {
17
+ return text + ADD_IMPORT;
18
+ }
19
+ export const vue3Loader = new URL(import.meta.resolve(import.meta.url)).pathname;
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@esmx/rspack-vue",
3
+ "description": "A high-performance Vue integration for Esmx microfrontend framework, providing Vue 2/3 support with SSR and Module Federation capabilities.",
4
+ "author": {
5
+ "name": "lzxb",
6
+ "url": "https://github.com/lzxb"
7
+ },
8
+ "contributors": [
9
+ {
10
+ "name": "RockShi1994",
11
+ "url": "https://github.com/RockShi1994"
12
+ },
13
+ {
14
+ "name": "jerrychan7",
15
+ "url": "https://github.com/jerrychan7"
16
+ }
17
+ ],
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/js-esm/esmx.git",
21
+ "directory": "packages/rspack-vue"
22
+ },
23
+ "homepage": "https://github.com/js-esm/esmx",
24
+ "bugs": {
25
+ "url": "https://github.com/js-esm/esmx/issues"
26
+ },
27
+ "template": "library-node",
28
+ "license": "MIT",
29
+ "keywords": [
30
+ "Vue",
31
+ "Vue 2",
32
+ "Vue 3",
33
+ "Rspack",
34
+ "SSR",
35
+ "Module Federation",
36
+ "High Performance",
37
+ "Build Tool",
38
+ "Development Experience",
39
+ "Hot Module Replacement",
40
+ "TypeScript"
41
+ ],
42
+ "scripts": {
43
+ "lint:js": "biome check --write --no-errors-on-unmatched",
44
+ "lint:css": "stylelint '**/*.{css,vue}' --fix --aei",
45
+ "lint:type": "tsc --noEmit",
46
+ "test": "vitest run --pass-with-no-tests",
47
+ "coverage": "vitest run --coverage --pass-with-no-tests",
48
+ "build": "unbuild"
49
+ },
50
+ "peerDependencies": {
51
+ "@esmx/core": "*",
52
+ "vue": ">=2.7.8 || >=3.0.0"
53
+ },
54
+ "dependencies": {
55
+ "@esmx/rspack": "3.0.0-rc.10",
56
+ "vue-style-loader": "^4.1.3",
57
+ "vue2-loader": "npm:vue-loader@15.11.1",
58
+ "vue3-loader": "npm:vue-loader@^17.4.2"
59
+ },
60
+ "devDependencies": {
61
+ "@biomejs/biome": "1.9.4",
62
+ "@esmx/core": "3.0.0-rc.10",
63
+ "@esmx/lint": "3.0.0-rc.10",
64
+ "@types/node": "22.13.10",
65
+ "@vitest/coverage-v8": "3.0.8",
66
+ "stylelint": "16.15.0",
67
+ "typescript": "5.8.2",
68
+ "unbuild": "2.0.0",
69
+ "vitest": "3.0.8"
70
+ },
71
+ "version": "3.0.0-rc.10",
72
+ "type": "module",
73
+ "private": false,
74
+ "exports": {
75
+ ".": {
76
+ "import": "./dist/index.mjs",
77
+ "types": "./dist/index.d.ts"
78
+ }
79
+ },
80
+ "module": "dist/index.mjs",
81
+ "types": "./dist/index.d.ts",
82
+ "files": [
83
+ "lib",
84
+ "src",
85
+ "dist",
86
+ "*.mjs",
87
+ "template",
88
+ "public"
89
+ ],
90
+ "gitHead": "4a528ffecfdc6f2c6e7d97bc952427745f467691"
91
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from '@esmx/rspack';
2
+ export * from './vue';
@@ -0,0 +1,110 @@
1
+ import type { Esmx } from '@esmx/core';
2
+ import { createRspackHtmlApp, rspack } from '@esmx/rspack';
3
+ import { VueLoaderPlugin as VueLoader2Plugin } from 'vue2-loader';
4
+ import { VueLoaderPlugin as VueLoader3Plugin } from 'vue3-loader';
5
+ import type { RspackVueAppOptions } from './vue';
6
+ import { vue2Loader } from './vue2-loader';
7
+ import { vue3Loader } from './vue3-loader';
8
+
9
+ type VueType = '2' | '3';
10
+
11
+ export function createRspackVueApp(
12
+ esmx: Esmx,
13
+ vueType: VueType,
14
+ options?: RspackVueAppOptions
15
+ ) {
16
+ return createRspackHtmlApp(esmx, {
17
+ ...options,
18
+ loaders: {
19
+ styleLoader: new URL(import.meta.resolve('vue-style-loader'))
20
+ .pathname,
21
+ ...options?.loaders
22
+ },
23
+ config(context) {
24
+ const { config, buildTarget } = context;
25
+ // 支持 Vue 拓展名
26
+ config.resolve = {
27
+ ...config.resolve,
28
+ extensions: [...(config.resolve?.extensions ?? []), '.vue']
29
+ };
30
+ config.plugins = config.plugins || [];
31
+ switch (vueType) {
32
+ case '2':
33
+ // @ts-ignore
34
+ config.plugins.push(new VueLoader2Plugin());
35
+ break;
36
+ case '3':
37
+ config.plugins.push(new VueLoader3Plugin());
38
+ break;
39
+ }
40
+ // 设置 Vue 相关的环境变量
41
+ if (buildTarget === 'client') {
42
+ config.plugins.push(
43
+ new rspack.DefinePlugin({
44
+ 'process.env.VUE_ENV': JSON.stringify(buildTarget)
45
+ })
46
+ );
47
+ }
48
+ // 设置 vue-loader
49
+ const vueRuleUse: rspack.RuleSetUse = [
50
+ {
51
+ loader: new URL(import.meta.resolve(`vue${vueType}-loader`))
52
+ .pathname,
53
+ options: {
54
+ ...options?.vueLoader,
55
+ experimentalInlineMatchResource: true,
56
+ optimizeSSR: buildTarget === 'server'
57
+ }
58
+ }
59
+ ];
60
+ switch (vueType) {
61
+ case '2':
62
+ vueRuleUse.unshift(vue2Loader);
63
+ break;
64
+ case '3':
65
+ vueRuleUse.unshift(vue3Loader);
66
+ break;
67
+ }
68
+ config.module = {
69
+ ...config.module,
70
+ rules: [
71
+ ...(config.module?.rules ?? []),
72
+ {
73
+ test: /\.vue$/,
74
+ use: vueRuleUse
75
+ }
76
+ ]
77
+ };
78
+ // 设置 vue 别名
79
+ let vueAlias: string | null = null;
80
+ switch (vueType) {
81
+ case '2':
82
+ vueAlias = 'vue/dist/vue.esm.js';
83
+ break;
84
+ case '3':
85
+ vueAlias = 'vue/dist/vue.runtime.esm-browser.js';
86
+ break;
87
+ }
88
+ if (vueAlias) {
89
+ config.resolve!.alias = {
90
+ ...config.resolve!.alias!,
91
+ vue$: vueAlias
92
+ };
93
+ }
94
+ // 设置 vue 相关忽略信息。
95
+ if (vueType === '2') {
96
+ config.ignoreWarnings = [
97
+ ...(config.ignoreWarnings ?? []),
98
+ (warning) => {
99
+ // @ts-ignore
100
+ return warning.moduleDescriptor.name.includes(
101
+ 'vue-server-renderer'
102
+ );
103
+ }
104
+ ];
105
+ }
106
+ // 设置自定义配置
107
+ options?.config?.(context);
108
+ }
109
+ });
110
+ }
package/src/vue.ts ADDED
@@ -0,0 +1,69 @@
1
+ import type { Esmx } from '@esmx/core';
2
+ import type { RspackHtmlAppOptions } from '@esmx/rspack';
3
+ import { createRspackVueApp } from './vue-core';
4
+
5
+ export interface RspackVueAppOptions extends RspackHtmlAppOptions {
6
+ /**
7
+ * vue-loader 配置项
8
+ *
9
+ * 用于配置 Vue 单文件组件的编译选项,完整选项参考:
10
+ * https://github.com/vuejs/vue-loader
11
+ */
12
+ vueLoader?: Record<string, any>;
13
+ }
14
+
15
+ /**
16
+ * 创建 Vue 2 应用构建器
17
+ *
18
+ * @param esmx - Esmx 实例
19
+ * @param options - Rspack Vue 应用配置项
20
+ * @returns 返回一个 Promise,解析为构建好的应用实例
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * import type { EsmxOptions } from '@esmx/core';
25
+ *
26
+ * export default {
27
+ * async devApp(esmx) {
28
+ * return import('@esmx/rspack-vue').then((m) =>
29
+ * m.createRspackVue2App(esmx, {
30
+ * config({ config }) {
31
+ * // 自定义 Rspack 配置
32
+ * }
33
+ * })
34
+ * );
35
+ * }
36
+ * } satisfies EsmxOptions;
37
+ * ```
38
+ */
39
+ export function createRspackVue2App(esmx: Esmx, options?: RspackVueAppOptions) {
40
+ return createRspackVueApp(esmx, '2', options);
41
+ }
42
+
43
+ /**
44
+ * 创建 Vue 3 应用构建器
45
+ *
46
+ * @param esmx - Esmx 实例
47
+ * @param options - Rspack Vue 应用配置项
48
+ * @returns 返回一个 Promise,解析为构建好的应用实例
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * import type { EsmxOptions } from '@esmx/core';
53
+ *
54
+ * export default {
55
+ * async devApp(esmx) {
56
+ * return import('@esmx/rspack-vue').then((m) =>
57
+ * m.createRspackVue3App(esmx, {
58
+ * config({ config }) {
59
+ * // 自定义 Rspack 配置
60
+ * }
61
+ * })
62
+ * );
63
+ * }
64
+ * } satisfies EsmxOptions;
65
+ * ```
66
+ */
67
+ export function createRspackVue3App(esmx: Esmx, options?: RspackVueAppOptions) {
68
+ return createRspackVueApp(esmx, '3', options);
69
+ }
@@ -0,0 +1,28 @@
1
+ import type { rspack } from '@esmx/rspack';
2
+ const FIX_ESM = `api.install(require('vue').default)`;
3
+ const ADD_IMPORT = `
4
+ function initImport () {
5
+ const mixins = Array.isArray(component.options.mixins) ? component.options.mixins : [];
6
+ mixins.push({
7
+ serverPrefetch () {
8
+ this.$ssrContext?.importMetaSet?.add(import.meta);
9
+ }
10
+ });
11
+ component.options.mixins = mixins;
12
+ }
13
+ initImport();
14
+ export default component.exports
15
+ `;
16
+
17
+ export default function (this: rspack.LoaderContext, text: string) {
18
+ // 修复不支持热更新的 BUG
19
+ text = text.replaceAll(`api.install(require('vue'))`, FIX_ESM);
20
+ // 添加 CSS 依赖收集
21
+ if (typeof this.target === 'string' && this.target.includes('node')) {
22
+ text = text.replaceAll('export default component.exports', ADD_IMPORT);
23
+ }
24
+ return text;
25
+ }
26
+
27
+ export const vue2Loader = new URL(import.meta.resolve(import.meta.url))
28
+ .pathname;
@@ -0,0 +1,24 @@
1
+ import type { rspack } from '@esmx/rspack';
2
+
3
+ const ADD_IMPORT = `
4
+ import { useSSRContext } from 'vue';
5
+ function initImport () {
6
+
7
+ const mixins = Array.isArray(__exports__.mixins) ? __exports__.mixins : [];
8
+ mixins.push({
9
+ created () {
10
+ const ctx = useSSRContext();
11
+ ctx?.importMetaSet?.add(import.meta);
12
+ }
13
+ });
14
+ __exports__.mixins = mixins;
15
+ }
16
+ initImport();
17
+ `;
18
+
19
+ export default function (this: rspack.LoaderContext, text: string) {
20
+ return text + ADD_IMPORT;
21
+ }
22
+
23
+ export const vue3Loader = new URL(import.meta.resolve(import.meta.url))
24
+ .pathname;