@lark-apaas/fullstack-rspack-preset 1.0.40 → 1.0.41

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/lib/preset.js CHANGED
@@ -35,6 +35,8 @@ function createRecommendRspackConfig(options) {
35
35
  const assetsCDNPath = publicPath + '/';
36
36
  const rootDir = process.cwd();
37
37
  const serverPort = process.env.SERVER_PORT || '3000';
38
+ // 提前创建实例,以便在 plugins 和 setupMiddlewares 中复用
39
+ const staticAssetsPlugin = new static_assets_plugin_1.default({ clientBasePath, rootDir });
38
40
  return {
39
41
  mode: isDev ? 'development' : 'production',
40
42
  cache: false,
@@ -206,7 +208,7 @@ function createRecommendRspackConfig(options) {
206
208
  // 生产环境:为旧浏览器提供 polyfill(仅在需要时加载)
207
209
  !isDev && new polyfill_plugin_1.default(),
208
210
  // 静态资源插件 - 支持 @shared/static/* 导入
209
- new static_assets_plugin_1.default({ clientBasePath, rootDir }),
211
+ staticAssetsPlugin,
210
212
  // 开发环境下,解析路由
211
213
  needRoutes &&
212
214
  new route_parser_plugin_1.default({
@@ -348,6 +350,8 @@ function createRecommendRspackConfig(options) {
348
350
  },
349
351
  setupMiddlewares: (middlewares, devServer) => {
350
352
  if (devServer.app) {
353
+ // 开发环境下提供 shared/static 文件服务,对齐 Vite preset 的 configureServer 中间件
354
+ devServer.app.use(staticAssetsPlugin.createDevMiddleware());
351
355
  (0, dev_server_snapdom_proxy_1.registerSnapDomProxyMiddleware)(devServer.app, { baseUrl: clientBasePath });
352
356
  (0, devtool_kits_1.registerMiddlewares)(devServer.app, [
353
357
  (0, devtool_kits_1.createDevLogsMiddleware)({ logDir: process.env.LOG_DIR || './logs' }),
@@ -0,0 +1,9 @@
1
+ interface EnvironmentInjectionPluginOptions {
2
+ environment?: string;
3
+ }
4
+ declare class EnvironmentInjectionPlugin {
5
+ private options;
6
+ constructor(options?: EnvironmentInjectionPluginOptions);
7
+ apply(compiler: unknown): void;
8
+ }
9
+ export default EnvironmentInjectionPlugin;
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class EnvironmentInjectionPlugin {
4
+ constructor(options) {
5
+ this.options = options || {};
6
+ }
7
+ apply(compiler) {
8
+ const compilerLike = getCompilerLike(compiler);
9
+ if (!compilerLike)
10
+ return;
11
+ compilerLike.hooks.compilation.tap('EnvironmentInjectionPlugin', (compilation) => {
12
+ try {
13
+ const HtmlPlugin = resolveHtmlPlugin(compilerLike);
14
+ if (!HtmlPlugin) {
15
+ console.warn('EnvironmentInjectionPlugin: HtmlRspackPlugin not found');
16
+ return;
17
+ }
18
+ const hooks = HtmlPlugin.getHooks(compilation);
19
+ hooks.alterAssetTagGroups.tap('EnvironmentInjectionPlugin', (data) => {
20
+ const mapped = mapToWindowEnvironment(this.options.environment ??
21
+ process.env.FORCE_FRAMEWORK_ENVIRONMENT);
22
+ const envTag = {
23
+ tagName: 'script',
24
+ voidTag: false,
25
+ innerHTML: `(() => {
26
+ const templateValue = '{{environment}}';
27
+ const resolved =
28
+ templateValue && templateValue !== '{{environment}}'
29
+ ? templateValue
30
+ : ${JSON.stringify(mapped)};
31
+ window.ENVIRONMENT = resolved;
32
+ })();`,
33
+ attributes: {},
34
+ };
35
+ const headIndex = findMainJsIndex(data.headTags);
36
+ if (headIndex !== -1) {
37
+ data.headTags.splice(headIndex, 0, envTag);
38
+ return data;
39
+ }
40
+ const bodyIndex = findMainJsIndex(data.bodyTags);
41
+ if (bodyIndex !== -1) {
42
+ data.bodyTags.splice(bodyIndex, 0, envTag);
43
+ return data;
44
+ }
45
+ data.headTags.unshift(envTag);
46
+ return data;
47
+ });
48
+ }
49
+ catch (error) {
50
+ console.error('Error in EnvironmentInjectionPlugin:', error);
51
+ }
52
+ });
53
+ }
54
+ }
55
+ exports.default = EnvironmentInjectionPlugin;
56
+ function mapToWindowEnvironment(input) {
57
+ const value = (input || '').trim().toLowerCase();
58
+ if (value === 'boe')
59
+ return 'staging';
60
+ if (value === 'pre')
61
+ return 'gray';
62
+ if (value === 'online')
63
+ return 'online';
64
+ return '';
65
+ }
66
+ function findMainJsIndex(tags) {
67
+ if (!Array.isArray(tags))
68
+ return -1;
69
+ return tags.findIndex((tag) => {
70
+ if (!tag || tag.tagName !== 'script')
71
+ return false;
72
+ const src = tag.attributes?.src;
73
+ return typeof src === 'string' && src.includes('main.js');
74
+ });
75
+ }
76
+ function getCompilerLike(input) {
77
+ if (!input || typeof input !== 'object')
78
+ return;
79
+ const hooks = input.hooks;
80
+ if (!hooks || typeof hooks !== 'object')
81
+ return;
82
+ const compilation = hooks.compilation;
83
+ if (!compilation || typeof compilation !== 'object')
84
+ return;
85
+ const tap = compilation.tap;
86
+ if (typeof tap !== 'function')
87
+ return;
88
+ return input;
89
+ }
90
+ function resolveHtmlPlugin(compiler) {
91
+ const fromWebpack = getHtmlPluginLike(compiler.webpack?.HtmlRspackPlugin);
92
+ if (fromWebpack)
93
+ return fromWebpack;
94
+ const fromRspack = getHtmlPluginLike(compiler.rspack?.HtmlRspackPlugin);
95
+ if (fromRspack)
96
+ return fromRspack;
97
+ const fromCtor = getHtmlPluginLike(compiler.constructor?.webpack?.HtmlRspackPlugin);
98
+ if (fromCtor)
99
+ return fromCtor;
100
+ return;
101
+ }
102
+ function getHtmlPluginLike(value) {
103
+ if (!value)
104
+ return;
105
+ const type = typeof value;
106
+ if (type !== 'function' && type !== 'object')
107
+ return;
108
+ const getHooks = value.getHooks;
109
+ if (typeof getHooks !== 'function')
110
+ return;
111
+ return value;
112
+ }
@@ -9,6 +9,7 @@
9
9
  * import config from '@shared/static/config.json';
10
10
  * import logoUrl from '@shared/static/images/logo.png';
11
11
  */
12
+ import type { IncomingMessage, ServerResponse } from 'http';
12
13
  import type { Compiler } from '@rspack/core';
13
14
  export interface StaticAssetsPluginOptions {
14
15
  /**
@@ -48,6 +49,11 @@ export declare class StaticAssetsPlugin {
48
49
  * Get the script content for __STATIC_JSON__ injection
49
50
  */
50
51
  private getStaticJsonScriptContent;
52
+ /**
53
+ * Create a dev server middleware that serves static files from shared/static.
54
+ * This aligns with the Vite preset's configureServer middleware.
55
+ */
56
+ createDevMiddleware(): (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
51
57
  apply(compiler: Compiler): void;
52
58
  }
53
59
  export default StaticAssetsPlugin;
@@ -49,6 +49,30 @@ exports.StaticAssetsPlugin = void 0;
49
49
  const fs = __importStar(require("fs"));
50
50
  const path = __importStar(require("path"));
51
51
  const glob_1 = require("glob");
52
+ const MIME_TYPES = {
53
+ '.json': 'application/json',
54
+ '.png': 'image/png',
55
+ '.jpg': 'image/jpeg',
56
+ '.jpeg': 'image/jpeg',
57
+ '.gif': 'image/gif',
58
+ '.svg': 'image/svg+xml',
59
+ '.webp': 'image/webp',
60
+ '.ico': 'image/x-icon',
61
+ '.woff': 'font/woff',
62
+ '.woff2': 'font/woff2',
63
+ '.ttf': 'font/ttf',
64
+ '.eot': 'application/vnd.ms-fontobject',
65
+ '.otf': 'font/otf',
66
+ '.css': 'text/css',
67
+ '.js': 'application/javascript',
68
+ '.txt': 'text/plain',
69
+ '.html': 'text/html',
70
+ '.xml': 'application/xml',
71
+ '.pdf': 'application/pdf',
72
+ '.mp3': 'audio/mpeg',
73
+ '.mp4': 'video/mp4',
74
+ '.webm': 'video/webm',
75
+ };
52
76
  const SHARED_STATIC_PREFIX = '@shared/static/';
53
77
  const PLUGIN_NAME = 'StaticAssetsPlugin';
54
78
  class StaticAssetsPlugin {
@@ -127,6 +151,47 @@ class StaticAssetsPlugin {
127
151
  }
128
152
  return `window.__STATIC_JSON__ = ${JSON.stringify(jsonData)};`;
129
153
  }
154
+ /**
155
+ * Create a dev server middleware that serves static files from shared/static.
156
+ * This aligns with the Vite preset's configureServer middleware.
157
+ */
158
+ createDevMiddleware() {
159
+ const staticDir = this.staticDir;
160
+ const clientBasePath = this.options.clientBasePath || '';
161
+ return (req, res, next) => {
162
+ const staticPrefix = `${clientBasePath}/static/`;
163
+ const url = req.url || '';
164
+ if (!url.startsWith(staticPrefix)) {
165
+ return next();
166
+ }
167
+ const relativePath = url.slice(staticPrefix.length).split('?')[0];
168
+ const filePath = path.join(staticDir, relativePath);
169
+ // Security: prevent path traversal
170
+ const normalizedPath = path.normalize(filePath);
171
+ if (!normalizedPath.startsWith(staticDir)) {
172
+ res.statusCode = 403;
173
+ res.end('Forbidden');
174
+ return;
175
+ }
176
+ if (!fs.existsSync(filePath)) {
177
+ res.statusCode = 404;
178
+ res.end('Not Found');
179
+ return;
180
+ }
181
+ const stat = fs.statSync(filePath);
182
+ if (stat.isDirectory()) {
183
+ res.statusCode = 403;
184
+ res.end('Forbidden');
185
+ return;
186
+ }
187
+ const ext = path.extname(filePath).toLowerCase();
188
+ const contentType = MIME_TYPES[ext] || 'application/octet-stream';
189
+ res.setHeader('Content-Type', contentType);
190
+ res.setHeader('Cache-Control', 'no-cache');
191
+ const stream = fs.createReadStream(filePath);
192
+ stream.pipe(res);
193
+ };
194
+ }
130
195
  apply(compiler) {
131
196
  const { clientBasePath } = this.options;
132
197
  // Create a temporary directory for virtual modules
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-rspack-preset",
3
- "version": "1.0.40",
3
+ "version": "1.0.41",
4
4
  "files": [
5
5
  "lib",
6
6
  "patches",
@@ -31,7 +31,6 @@
31
31
  "@babel/parser": "^7.28.0",
32
32
  "@babel/traverse": "^7.28.0",
33
33
  "@babel/types": "^7.28.2",
34
- "glob": "^11.0.0",
35
34
  "@lark-apaas/devtool-kits": "^1.2.18",
36
35
  "@lark-apaas/miaoda-inspector-babel-plugin": "^1.0.0",
37
36
  "@lark-apaas/miaoda-inspector-jsx-runtime": "^1.0.1",
@@ -45,6 +44,7 @@
45
44
  "dotenv": "^16.4.5",
46
45
  "echarts": "^6.0.0",
47
46
  "echarts-for-react": "^3.0.2",
47
+ "glob": "^11.0.0",
48
48
  "lightningcss": "^1.28.0",
49
49
  "patch-package": "^8.0.0",
50
50
  "postcss-import": "^16.1.1",