@bundlekit/bundler-rollup 0.0.1
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/dist/DevServer.d.ts +41 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.mjs +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Logger } from "@bundlekit/shared-utils";
|
|
2
|
+
export interface ProxyRule {
|
|
3
|
+
/** 代理目标地址,如 "http://localhost:4000" */
|
|
4
|
+
target: string;
|
|
5
|
+
/** 是否改写 Host 头为目标地址,默认 true */
|
|
6
|
+
changeOrigin?: boolean;
|
|
7
|
+
/** 是否验证 HTTPS 证书,默认 false */
|
|
8
|
+
secure?: boolean;
|
|
9
|
+
/** 路径重写函数 */
|
|
10
|
+
rewrite?: (reqPath: string) => string;
|
|
11
|
+
}
|
|
12
|
+
export interface DevServerOptions {
|
|
13
|
+
host: string;
|
|
14
|
+
port: number;
|
|
15
|
+
/** 打包输出目录(静态文件根目录) */
|
|
16
|
+
outDir: string;
|
|
17
|
+
/** 是否自动打开浏览器 */
|
|
18
|
+
open?: boolean;
|
|
19
|
+
/** 代理配置 */
|
|
20
|
+
proxy?: Record<string, string | ProxyRule>;
|
|
21
|
+
}
|
|
22
|
+
export declare class DevServer {
|
|
23
|
+
private server;
|
|
24
|
+
private sseClients;
|
|
25
|
+
private options;
|
|
26
|
+
private logger;
|
|
27
|
+
constructor(options: DevServerOptions, logger: Logger);
|
|
28
|
+
/** 向所有已连接的浏览器客户端发送 reload 信号 */
|
|
29
|
+
reload(): void;
|
|
30
|
+
/** 启动 HTTP 服务 */
|
|
31
|
+
start(): Promise<void>;
|
|
32
|
+
/** 关闭服务并断开所有 SSE 客户端 */
|
|
33
|
+
close(): void;
|
|
34
|
+
/** 把 URL 路径解析为实际文件路径,找不到返回 null,最终回退到 index.html(SPA) */
|
|
35
|
+
private resolveFilePath;
|
|
36
|
+
/** 尝试代理请求,匹配返回 true,未匹配返回 false */
|
|
37
|
+
private handleProxy;
|
|
38
|
+
/** 获取本机局域网 IPv4 地址 */
|
|
39
|
+
private getLocalIP;
|
|
40
|
+
private openBrowser;
|
|
41
|
+
}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("path"),t=require("fs"),r=require("rollup"),s=require("@rollup/plugin-node-resolve"),o=require("@rollup/plugin-commonjs"),n=require("@rollup/plugin-typescript"),i=require("@rollup/plugin-babel"),l=require("@rollup/plugin-image"),a=require("@rollup/plugin-json"),c=require("@rollup/plugin-replace"),u=require("rollup-plugin-postcss"),p=require("@bundlekit/shared-utils"),d=require("http"),h=require("https"),m=require("os"),g=require("child_process");const f={".html":"text/html; charset=utf-8",".js":"application/javascript; charset=utf-8",".mjs":"application/javascript; charset=utf-8",".cjs":"application/javascript; charset=utf-8",".css":"text/css; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml; charset=utf-8",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".eot":"application/vnd.ms-fontobject",".map":"application/json",".txt":"text/plain; charset=utf-8",".xml":"application/xml",".webp":"image/webp"},v="<script data-bundlekit=\"livereload\">\n(function () {\n var sse = new EventSource('/__bundlekit_sse');\n sse.addEventListener('message', function (e) {\n if (e.data === 'reload') {\n console.log('[bundlekit] livereload triggered');\n location.reload();\n }\n });\n sse.onerror = function () {\n sse.close();\n setTimeout(function () { location.reload(); }, 2000);\n };\n})();\n<\/script>";class y{constructor(e,t){this.server=null,this.sseClients=new Set,this.options=e,this.logger=t}reload(){const e=[];for(const t of this.sseClients)try{t.write("data: reload\n\n")}catch{e.push(t)}e.forEach(e=>this.sseClients.delete(e))}start(){return new Promise((r,s)=>{this.server=d.createServer(async(r,s)=>{const o=r.url??"/";if(o.startsWith("/__bundlekit_sse"))return s.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),s.write(":ok\n\n"),this.sseClients.add(s),void r.on("close",()=>this.sseClients.delete(s));if(await this.handleProxy(r,s))return;const n=this.resolveFilePath(o);if(!n)return s.writeHead(404,{"Content-Type":"text/plain"}),void s.end(`Cannot GET ${o}`);const i=e.extname(n).toLowerCase(),l=f[i]??"application/octet-stream";try{if(".html"===i){let e=t.readFileSync(n,"utf-8");e=e.includes("</body>")?e.replace("</body>",`${v}\n</body>`):e+v,s.writeHead(200,{"Content-Type":l}),s.end(e)}else{const e=t.statSync(n).size;s.writeHead(200,{"Content-Type":l,"Content-Length":e}),t.createReadStream(n).pipe(s)}}catch(e){this.logger.error(`[bundlekit] 读取文件失败: ${e.message}`),s.writeHead(500),s.end("Internal Server Error")}}),this.server.on("error",s),this.server.listen(this.options.port,this.options.host,()=>{const e=this.server.address().port,t=this.getLocalIP();this.logger.clearConsole("Dev Server 启动成功"),this.logger.done("服务已启动:","🌐"),this.logger.log(` - 本地: http://localhost:${e}`),this.logger.log(` - 网络: http://${t}:${e}`),this.logger.log(""),this.options.open&&this.openBrowser(`http://localhost:${e}`),r()})})}close(){for(const e of this.sseClients)try{e.end()}catch{}this.sseClients.clear(),this.server?.close(),this.server=null}resolveFilePath(r){let s=r.split("?")[0];try{s=decodeURIComponent(s)}catch{}const o=this.options.outDir,n=[e.join(o,s),e.join(o,s,"index.html"),e.join(o,"index.html")];for(const e of n)try{if(t.statSync(e).isFile())return e}catch{}return null}async handleProxy(e,t){const r=this.options.proxy??{},s=e.url??"/";for(const[o,n]of Object.entries(r)){if(!s.startsWith(o))continue;const r="string"==typeof n?{target:n}:n;let i;try{i=new URL(r.target)}catch{return this.logger.error(`[bundlekit] 代理目标 URL 无效: ${r.target}`),t.writeHead(502),t.end("Bad Gateway: invalid proxy target"),!0}const l=r.rewrite?r.rewrite(s):s,a="https:"===i.protocol,c=a?h:d,u=a?443:80;return new Promise(s=>{const o=c.request({hostname:i.hostname,port:Number(i.port)||u,path:l,method:e.method,headers:{...e.headers,...!1!==r.changeOrigin?{host:i.host}:{}}},e=>{t.writeHead(e.statusCode??200,e.headers),e.pipe(t,{end:!0}),s(!0)});o.on("error",e=>{this.logger.error(`[bundlekit] 代理请求失败: ${e.message}`),t.headersSent||(t.writeHead(502),t.end(`Bad Gateway: ${e.message}`)),s(!0)}),e.pipe(o,{end:!0})})}return!1}getLocalIP(){for(const e of Object.values(m.networkInterfaces()))for(const t of e??[])if("IPv4"===t.family&&!t.internal)return t.address;return"localhost"}openBrowser(e){const t="darwin"===process.platform?`open "${e}"`:"win32"===process.platform?`start "" "${e}"`:`xdg-open "${e}"`;g.exec(t,e=>{e&&this.logger.warn(`[bundlekit] 打开浏览器失败: ${e.message}`)})}}const x={es:".mjs",esm:".mjs",cjs:".cjs",commonjs:".cjs",umd:".umd.js",iife:".iife.js"},w=e=>({commonjs:"cjs",esm:"es",es:"es",cjs:"cjs",umd:"umd",iife:"iife"}[e]??"es");const j=new Set(["cache","context","experimentalCacheExpiry","experimentalLogSideEffects","external","fs","input","jsx","logLevel","makeAbsoluteExternalsRelative","maxParallelFileOps","moduleContext","onLog","onwarn","output","perf","plugins","preserveEntrySignatures","preserveSymlinks","shimMissingExports","strictDeprecations","treeshake","watch"]);function S(e){return Object.fromEntries(Object.entries(e).filter(([e])=>j.has(e)))}module.exports=class{constructor(e,t){this.logger=new p.Logger,this.devServerConfig=null,this.name="@bundlekit/bundler-rollup",this.mode=t,this.context=e.context||process.cwd(),this.fse=new p.FileManager(this.context)}transformConfig(r){const p=[".js",".jsx",".ts",".tsx"],d=r.config?.[this.mode]||r.config?.development||{},h="node"===d.target,m=d.entry?"string"==typeof d.entry?d.entry:Object.values(d.entry)[0]:e.resolve(this.context,"src/index.ts"),g=(d.output&&!Array.isArray(d.output)?d.output.dir:void 0)||(Array.isArray(d.output)?d.output[0]?.dir:void 0)||"dist",f=e.resolve(this.context,g),v=d.css||{},y=!0===d.library,j=d.libraryName,S=d.output?.formats,b=Array.isArray(S)?S:[S||"es"],C=d.output?.filename||"index.js",E=/\[.+?\]/.test(C)?"index.js":C,$=C.replace(/\[.+?\]/g,"").replace(/\.[^.]+$/,"")||"index",k="production"===this.mode?"production":"development",R=[c({preventAssignment:!0,values:{"process.env.NODE_ENV":JSON.stringify(k),"import.meta.env.MODE":JSON.stringify(k),"import.meta.env.PROD":String("production"===k),"import.meta.env.DEV":String("production"!==k),"import.meta.env.SSR":"false","import.meta.env":JSON.stringify({MODE:k,DEV:"production"!==k,PROD:"production"===k,SSR:!1})}}),s({extensions:p,browser:!0,preferBuiltins:!1}),o(),a(),l(),u({extract:v.extract||!1,modules:v.modules||!1,sourceMap:v.sourcemap||!1,use:[...v.loaders?.includes("less")?["less"]:[],...v.loaders?.includes("sass")||v.loaders?.includes("scss")?["sass"]:[]]}),n({tsconfig:e.resolve(this.context,"tsconfig.json"),outDir:f,declaration:y,noEmit:!1,sourceMap:d.js?.sourcemap??!1}),i({babelHelpers:"bundled",extensions:p,exclude:["node_modules/**"],presets:[["@babel/preset-env",{modules:!1}],"@babel/preset-typescript"]})];if(!y&&!h){const r=d.pages,s=r?.[0];R.push((O={context:this.context,template:s?.template,filename:s?.filename||"index.html",inject:s?.inject||"body"},{name:"bundlekit-html",generateBundle(r,s){const o=Object.keys(s).filter(e=>"chunk"===s[e].type).map(t=>e.basename(t)),n=Object.keys(s).filter(e=>"asset"===s[e].type&&e.endsWith(".css")).map(t=>e.basename(t)).map(e=>` <link rel="stylesheet" href="${e}">`).join("\n"),i=o.map(e=>` <script src="${e}"><\/script>`).join("\n");let l;const a=O.template?e.resolve(O.context,O.template):null;if(a&&t.existsSync(a)){l=t.readFileSync(a,"utf-8"),n&&(l=l.includes("</head>")?l.replace("</head>",`${n}\n</head>`):n+"\n"+l);const e="head"===O.inject?"</head>":"</body>";l=l.includes(e)?l.replace(e,`${i}\n${e}`):l+i}else l=["<!DOCTYPE html>",'<html lang="en">',"<head>",' <meta charset="UTF-8">',' <meta name="viewport" content="width=device-width, initial-scale=1.0">'," <title>App</title>",...n?[n]:[],..."head"===O.inject?[i]:[],"</head>","<body>",' <div id="root"></div>',..."head"!==O.inject?[i]:[],"</body>","</html>"].join("\n");this.emitFile({type:"asset",fileName:O.filename,source:l})}}))}var O;const D=h?this.resolveServerExternals(d):d.externals||[];let A;if(h){const t=d.ssr,r="esm"===t?.output?.formats?"es":"cjs";A={file:e.resolve(f,t?.output?.filename||"server.cjs"),format:r,sourcemap:d.js?.sourcemap||!1,exports:"named",inlineDynamicImports:!0}}else if(y&&b.length>1)A=b.map(t=>{const r=w(t),s=x[t]??".js";return{file:e.resolve(f,`${$}${s}`),format:r,sourcemap:d.js?.sourcemap||!1,name:["umd","iife"].includes(r)?j||e.basename(String(m),e.extname(String(m))):void 0,inlineDynamicImports:["umd","iife"].includes(r),exports:"named"}});else{const t=b[0]??"es",r=w(t);A={file:e.resolve(f,y?`${$}${x[t]??".js"}`:E),format:r,sourcemap:d.js?.sourcemap||!1,name:["umd","iife"].includes(r)?j||e.basename(String(m),e.extname(String(m))):void 0,inlineDynamicImports:["umd","iife"].includes(r)}}return this.devServerConfig={host:d.devServer?.host??"0.0.0.0",port:d.devServer?.port??3e3,open:d.devServer?.open??!1,proxy:d.devServer?.proxy??{},outDir:f,library:y},{input:e.resolve(this.context,String(m)),output:A,plugins:R,external:D}}validateConfig(e,t){return!t||p.validateBuildConfig(t,this.mode).valid}resolveServerExternals(r){const s=r.ssr?.externals;if(Array.isArray(s))return s;const o=new Set;try{const r=e.join(this.context,"package.json");if(t.existsSync(r)){const e=JSON.parse(t.readFileSync(r,"utf-8"));Object.keys(e.dependencies||{}).forEach(e=>o.add(e)),Object.keys(e.peerDependencies||{}).forEach(e=>o.add(e))}}catch{}return t=>{if(t.startsWith("node:"))return!0;if(t.startsWith(".")||e.isAbsolute(t))return!1;if(o.has(t))return!0;for(const e of o)if(t===e||t.startsWith(e+"/"))return!0;return!1}}async run(e){try{this.logger.info("开始使用rollup进行打包");e.__isServerPass;switch(this.mode){case"development":if((!this.devServerConfig||!1!==this.devServerConfig.library||!Array.isArray(e.output))&&("cjs"===e.output?.format&&e.output?.file?.endsWith(".cjs"))){await this.prodBuild(e);break}await this.devBuild(e);break;case"production":case"test":case"staging":case"gray":await this.prodBuild(e)}}catch(e){throw this.logger.error(`打包失败, 错误信息: ${e}`),e}}async devBuild(t){const s=this.devServerConfig,o=s?.library??!1,n=S(t),i=r.watch({...n,watch:{clearScreen:!1,exclude:"node_modules/**"}});if(o)return this.logger.info("rollup library watch 模式已启动","rollup"),void i.on("event",e=>{"START"===e.code&&this.logger.log("rollup 开始重新构建...","rollup"),"END"===e.code&&this.logger.done("rollup 构建完成","rollup"),"ERROR"===e.code&&this.logger.error(`rollup 构建错误: ${e.error}`,"rollup"),e.result&&e.result.close()});const l=new y({host:s?.host??"0.0.0.0",port:s?.port??3e3,outDir:s?.outDir??e.resolve(this.context,"dist"),open:s?.open??!1,proxy:s?.proxy??{}},this.logger);await new Promise(e=>{let t=!1;i.on("event",async r=>{"START"===r.code&&this.logger.log("rollup 开始重新构建...","rollup"),"END"===r.code&&(this.logger.done("rollup 构建完成","rollup"),t?l.reload():(t=!0,await l.start(),e())),"ERROR"===r.code&&(this.logger.error(`rollup 构建错误: ${r.error}`,"rollup"),t||e()),r.result&&r.result.close()})})}async prodBuild(e){const t=S(e),s=await r.rollup(t),o=Array.isArray(t.output)?t.output:[t.output];for(const e of o)await s.write(e);this.logger.done("rollup 生产构建完成","rollup"),await s.close()}async createSSRMiddleware(t,s){const o=t.config?.[this.mode]||t.config?.development,n=o?.ssr;if(!n)throw new Error("ssr config not found in envConfig");const i=p.buildSSRView(t,this.mode),l=S(this.transformConfig(i)),a=e.resolve(this.context,n.output.dir),c=n.output.filename||"server.cjs",u=e.resolve(a,c);let d=!1,h=[];r.watch({...l,watch:{clearScreen:!1,exclude:"node_modules/**"}}).on("event",e=>{if("END"===e.code){d=!0;const e=h;h=[],e.forEach(e=>e())}"ERROR"===e.code&&this.logger.error(`rollup server compiler 错误: ${e.error}`,"rollup"),e.result&&e.result.close()});return[p.createSSRRequestHandler({context:this.context,ssrConfig:n,serverBundlePath:()=>u,waitUntilReady:()=>d?Promise.resolve():new Promise(e=>h.push(e)),onError:e=>this.logger.error(`SSR 渲染失败: ${e?.message??e}`,"rollup")})]}};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { RollupOptions } from "rollup";
|
|
2
|
+
import type { IBuildConfig, IBuildToolAdapter, IService, IBuildEnv, IRequestHandler, ISSRMiddlewareCtx } from "@bundlekit/shared-utils";
|
|
3
|
+
export default class rollupBundler implements IBuildToolAdapter<RollupOptions> {
|
|
4
|
+
private context;
|
|
5
|
+
private mode;
|
|
6
|
+
private logger;
|
|
7
|
+
private fse;
|
|
8
|
+
/** transformConfig 阶段存储,run 阶段使用 */
|
|
9
|
+
private devServerConfig;
|
|
10
|
+
name: string;
|
|
11
|
+
constructor(api: IService, mode: IBuildEnv);
|
|
12
|
+
transformConfig(config: IBuildConfig): RollupOptions;
|
|
13
|
+
validateConfig(config: RollupOptions, buildConfig?: IBuildConfig): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* SSR server pass externals
|
|
16
|
+
*/
|
|
17
|
+
private resolveServerExternals;
|
|
18
|
+
run(config: RollupOptions): Promise<void>;
|
|
19
|
+
private devBuild;
|
|
20
|
+
private prodBuild;
|
|
21
|
+
/**
|
|
22
|
+
* Rollup dev SSR middleware(无 HMR 注入)
|
|
23
|
+
*
|
|
24
|
+
* 实现思路:
|
|
25
|
+
* 1. server bundle 用 rollup.watch 持续监听并写到磁盘
|
|
26
|
+
* 2. ssrHandler 每次请求等编译就绪 → 清 require cache → require → render
|
|
27
|
+
* 3. client 部分由用户自行处理(rollup dev 通常用 livereload,无原生 HMR)
|
|
28
|
+
*/
|
|
29
|
+
createSSRMiddleware(buildConfig: IBuildConfig, ctx: ISSRMiddlewareCtx): Promise<IRequestHandler[]>;
|
|
30
|
+
}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"path";import{readFileSync as t,statSync as r,createReadStream as o,existsSync as s}from"fs";import{watch as n,rollup as i}from"rollup";import l from"@rollup/plugin-node-resolve";import a from"@rollup/plugin-commonjs";import c from"@rollup/plugin-typescript";import p from"@rollup/plugin-babel";import u from"@rollup/plugin-image";import d from"@rollup/plugin-json";import m from"@rollup/plugin-replace";import h from"rollup-plugin-postcss";import{Logger as f,FileManager as g,validateBuildConfig as v,buildSSRView as y,createSSRRequestHandler as x}from"@bundlekit/shared-utils";import j from"http";import w from"https";import b from"os";import{exec as S}from"child_process";const C={".html":"text/html; charset=utf-8",".js":"application/javascript; charset=utf-8",".mjs":"application/javascript; charset=utf-8",".cjs":"application/javascript; charset=utf-8",".css":"text/css; charset=utf-8",".json":"application/json; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".svg":"image/svg+xml; charset=utf-8",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".eot":"application/vnd.ms-fontobject",".map":"application/json",".txt":"text/plain; charset=utf-8",".xml":"application/xml",".webp":"image/webp"},E="<script data-bundlekit=\"livereload\">\n(function () {\n var sse = new EventSource('/__bundlekit_sse');\n sse.addEventListener('message', function (e) {\n if (e.data === 'reload') {\n console.log('[bundlekit] livereload triggered');\n location.reload();\n }\n });\n sse.onerror = function () {\n sse.close();\n setTimeout(function () { location.reload(); }, 2000);\n };\n})();\n<\/script>";class ${constructor(e,t){this.server=null,this.sseClients=new Set,this.options=e,this.logger=t}reload(){const e=[];for(const t of this.sseClients)try{t.write("data: reload\n\n")}catch{e.push(t)}e.forEach(e=>this.sseClients.delete(e))}start(){return new Promise((s,n)=>{this.server=j.createServer(async(s,n)=>{const i=s.url??"/";if(i.startsWith("/__bundlekit_sse"))return n.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),n.write(":ok\n\n"),this.sseClients.add(n),void s.on("close",()=>this.sseClients.delete(n));if(await this.handleProxy(s,n))return;const l=this.resolveFilePath(i);if(!l)return n.writeHead(404,{"Content-Type":"text/plain"}),void n.end(`Cannot GET ${i}`);const a=e.extname(l).toLowerCase(),c=C[a]??"application/octet-stream";try{if(".html"===a){let e=t(l,"utf-8");e=e.includes("</body>")?e.replace("</body>",`${E}\n</body>`):e+E,n.writeHead(200,{"Content-Type":c}),n.end(e)}else{const e=r(l).size;n.writeHead(200,{"Content-Type":c,"Content-Length":e}),o(l).pipe(n)}}catch(e){this.logger.error(`[bundlekit] 读取文件失败: ${e.message}`),n.writeHead(500),n.end("Internal Server Error")}}),this.server.on("error",n),this.server.listen(this.options.port,this.options.host,()=>{const e=this.server.address().port,t=this.getLocalIP();this.logger.clearConsole("Dev Server 启动成功"),this.logger.done("服务已启动:","🌐"),this.logger.log(` - 本地: http://localhost:${e}`),this.logger.log(` - 网络: http://${t}:${e}`),this.logger.log(""),this.options.open&&this.openBrowser(`http://localhost:${e}`),s()})})}close(){for(const e of this.sseClients)try{e.end()}catch{}this.sseClients.clear(),this.server?.close(),this.server=null}resolveFilePath(t){let o=t.split("?")[0];try{o=decodeURIComponent(o)}catch{}const s=this.options.outDir,n=[e.join(s,o),e.join(s,o,"index.html"),e.join(s,"index.html")];for(const e of n)try{if(r(e).isFile())return e}catch{}return null}async handleProxy(e,t){const r=this.options.proxy??{},o=e.url??"/";for(const[s,n]of Object.entries(r)){if(!o.startsWith(s))continue;const r="string"==typeof n?{target:n}:n;let i;try{i=new URL(r.target)}catch{return this.logger.error(`[bundlekit] 代理目标 URL 无效: ${r.target}`),t.writeHead(502),t.end("Bad Gateway: invalid proxy target"),!0}const l=r.rewrite?r.rewrite(o):o,a="https:"===i.protocol,c=a?w:j,p=a?443:80;return new Promise(o=>{const s=c.request({hostname:i.hostname,port:Number(i.port)||p,path:l,method:e.method,headers:{...e.headers,...!1!==r.changeOrigin?{host:i.host}:{}}},e=>{t.writeHead(e.statusCode??200,e.headers),e.pipe(t,{end:!0}),o(!0)});s.on("error",e=>{this.logger.error(`[bundlekit] 代理请求失败: ${e.message}`),t.headersSent||(t.writeHead(502),t.end(`Bad Gateway: ${e.message}`)),o(!0)}),e.pipe(s,{end:!0})})}return!1}getLocalIP(){for(const e of Object.values(b.networkInterfaces()))for(const t of e??[])if("IPv4"===t.family&&!t.internal)return t.address;return"localhost"}openBrowser(e){const t="darwin"===process.platform?`open "${e}"`:"win32"===process.platform?`start "" "${e}"`:`xdg-open "${e}"`;S(t,e=>{e&&this.logger.warn(`[bundlekit] 打开浏览器失败: ${e.message}`)})}}const k={es:".mjs",esm:".mjs",cjs:".cjs",commonjs:".cjs",umd:".umd.js",iife:".iife.js"},O=e=>({commonjs:"cjs",esm:"es",es:"es",cjs:"cjs",umd:"umd",iife:"iife"}[e]??"es");const D=new Set(["cache","context","experimentalCacheExpiry","experimentalLogSideEffects","external","fs","input","jsx","logLevel","makeAbsoluteExternalsRelative","maxParallelFileOps","moduleContext","onLog","onwarn","output","perf","plugins","preserveEntrySignatures","preserveSymlinks","shimMissingExports","strictDeprecations","treeshake","watch"]);function R(e){return Object.fromEntries(Object.entries(e).filter(([e])=>D.has(e)))}class A{constructor(e,t){this.logger=new f,this.devServerConfig=null,this.name="@bundlekit/bundler-rollup",this.mode=t,this.context=e.context||process.cwd(),this.fse=new g(this.context)}transformConfig(r){const o=[".js",".jsx",".ts",".tsx"],n=r.config?.[this.mode]||r.config?.development||{},i="node"===n.target,f=n.entry?"string"==typeof n.entry?n.entry:Object.values(n.entry)[0]:e.resolve(this.context,"src/index.ts"),g=(n.output&&!Array.isArray(n.output)?n.output.dir:void 0)||(Array.isArray(n.output)?n.output[0]?.dir:void 0)||"dist",v=e.resolve(this.context,g),y=n.css||{},x=!0===n.library,j=n.libraryName,w=n.output?.formats,b=Array.isArray(w)?w:[w||"es"],S=n.output?.filename||"index.js",C=/\[.+?\]/.test(S)?"index.js":S,E=S.replace(/\[.+?\]/g,"").replace(/\.[^.]+$/,"")||"index",$="production"===this.mode?"production":"development",D=[m({preventAssignment:!0,values:{"process.env.NODE_ENV":JSON.stringify($),"import.meta.env.MODE":JSON.stringify($),"import.meta.env.PROD":String("production"===$),"import.meta.env.DEV":String("production"!==$),"import.meta.env.SSR":"false","import.meta.env":JSON.stringify({MODE:$,DEV:"production"!==$,PROD:"production"===$,SSR:!1})}}),l({extensions:o,browser:!0,preferBuiltins:!1}),a(),d(),u(),h({extract:y.extract||!1,modules:y.modules||!1,sourceMap:y.sourcemap||!1,use:[...y.loaders?.includes("less")?["less"]:[],...y.loaders?.includes("sass")||y.loaders?.includes("scss")?["sass"]:[]]}),c({tsconfig:e.resolve(this.context,"tsconfig.json"),outDir:v,declaration:x,noEmit:!1,sourceMap:n.js?.sourcemap??!1}),p({babelHelpers:"bundled",extensions:o,exclude:["node_modules/**"],presets:[["@babel/preset-env",{modules:!1}],"@babel/preset-typescript"]})];if(!x&&!i){const r=n.pages,o=r?.[0];D.push((R={context:this.context,template:o?.template,filename:o?.filename||"index.html",inject:o?.inject||"body"},{name:"bundlekit-html",generateBundle(r,o){const n=Object.keys(o).filter(e=>"chunk"===o[e].type).map(t=>e.basename(t)),i=Object.keys(o).filter(e=>"asset"===o[e].type&&e.endsWith(".css")).map(t=>e.basename(t)).map(e=>` <link rel="stylesheet" href="${e}">`).join("\n"),l=n.map(e=>` <script src="${e}"><\/script>`).join("\n");let a;const c=R.template?e.resolve(R.context,R.template):null;if(c&&s(c)){a=t(c,"utf-8"),i&&(a=a.includes("</head>")?a.replace("</head>",`${i}\n</head>`):i+"\n"+a);const e="head"===R.inject?"</head>":"</body>";a=a.includes(e)?a.replace(e,`${l}\n${e}`):a+l}else a=["<!DOCTYPE html>",'<html lang="en">',"<head>",' <meta charset="UTF-8">',' <meta name="viewport" content="width=device-width, initial-scale=1.0">'," <title>App</title>",...i?[i]:[],..."head"===R.inject?[l]:[],"</head>","<body>",' <div id="root"></div>',..."head"!==R.inject?[l]:[],"</body>","</html>"].join("\n");this.emitFile({type:"asset",fileName:R.filename,source:a})}}))}var R;const A=i?this.resolveServerExternals(n):n.externals||[];let P;if(i){const t=n.ssr,r="esm"===t?.output?.formats?"es":"cjs";P={file:e.resolve(v,t?.output?.filename||"server.cjs"),format:r,sourcemap:n.js?.sourcemap||!1,exports:"named",inlineDynamicImports:!0}}else if(x&&b.length>1)P=b.map(t=>{const r=O(t),o=k[t]??".js";return{file:e.resolve(v,`${E}${o}`),format:r,sourcemap:n.js?.sourcemap||!1,name:["umd","iife"].includes(r)?j||e.basename(String(f),e.extname(String(f))):void 0,inlineDynamicImports:["umd","iife"].includes(r),exports:"named"}});else{const t=b[0]??"es",r=O(t);P={file:e.resolve(v,x?`${E}${k[t]??".js"}`:C),format:r,sourcemap:n.js?.sourcemap||!1,name:["umd","iife"].includes(r)?j||e.basename(String(f),e.extname(String(f))):void 0,inlineDynamicImports:["umd","iife"].includes(r)}}return this.devServerConfig={host:n.devServer?.host??"0.0.0.0",port:n.devServer?.port??3e3,open:n.devServer?.open??!1,proxy:n.devServer?.proxy??{},outDir:v,library:x},{input:e.resolve(this.context,String(f)),output:P,plugins:D,external:A}}validateConfig(e,t){return!t||v(t,this.mode).valid}resolveServerExternals(r){const o=r.ssr?.externals;if(Array.isArray(o))return o;const n=new Set;try{const r=e.join(this.context,"package.json");if(s(r)){const e=JSON.parse(t(r,"utf-8"));Object.keys(e.dependencies||{}).forEach(e=>n.add(e)),Object.keys(e.peerDependencies||{}).forEach(e=>n.add(e))}}catch{}return t=>{if(t.startsWith("node:"))return!0;if(t.startsWith(".")||e.isAbsolute(t))return!1;if(n.has(t))return!0;for(const e of n)if(t===e||t.startsWith(e+"/"))return!0;return!1}}async run(e){try{this.logger.info("开始使用rollup进行打包");e.__isServerPass;switch(this.mode){case"development":if((!this.devServerConfig||!1!==this.devServerConfig.library||!Array.isArray(e.output))&&("cjs"===e.output?.format&&e.output?.file?.endsWith(".cjs"))){await this.prodBuild(e);break}await this.devBuild(e);break;case"production":case"test":case"staging":case"gray":await this.prodBuild(e)}}catch(e){throw this.logger.error(`打包失败, 错误信息: ${e}`),e}}async devBuild(t){const r=this.devServerConfig,o=r?.library??!1,s=R(t),i=n({...s,watch:{clearScreen:!1,exclude:"node_modules/**"}});if(o)return this.logger.info("rollup library watch 模式已启动","rollup"),void i.on("event",e=>{"START"===e.code&&this.logger.log("rollup 开始重新构建...","rollup"),"END"===e.code&&this.logger.done("rollup 构建完成","rollup"),"ERROR"===e.code&&this.logger.error(`rollup 构建错误: ${e.error}`,"rollup"),e.result&&e.result.close()});const l=new $({host:r?.host??"0.0.0.0",port:r?.port??3e3,outDir:r?.outDir??e.resolve(this.context,"dist"),open:r?.open??!1,proxy:r?.proxy??{}},this.logger);await new Promise(e=>{let t=!1;i.on("event",async r=>{"START"===r.code&&this.logger.log("rollup 开始重新构建...","rollup"),"END"===r.code&&(this.logger.done("rollup 构建完成","rollup"),t?l.reload():(t=!0,await l.start(),e())),"ERROR"===r.code&&(this.logger.error(`rollup 构建错误: ${r.error}`,"rollup"),t||e()),r.result&&r.result.close()})})}async prodBuild(e){const t=R(e),r=await i(t),o=Array.isArray(t.output)?t.output:[t.output];for(const e of o)await r.write(e);this.logger.done("rollup 生产构建完成","rollup"),await r.close()}async createSSRMiddleware(t,r){const o=t.config?.[this.mode]||t.config?.development,s=o?.ssr;if(!s)throw new Error("ssr config not found in envConfig");const i=y(t,this.mode),l=R(this.transformConfig(i)),a=e.resolve(this.context,s.output.dir),c=s.output.filename||"server.cjs",p=e.resolve(a,c);let u=!1,d=[];n({...l,watch:{clearScreen:!1,exclude:"node_modules/**"}}).on("event",e=>{if("END"===e.code){u=!0;const e=d;d=[],e.forEach(e=>e())}"ERROR"===e.code&&this.logger.error(`rollup server compiler 错误: ${e.error}`,"rollup"),e.result&&e.result.close()});return[x({context:this.context,ssrConfig:s,serverBundlePath:()=>p,waitUntilReady:()=>u?Promise.resolve():new Promise(e=>d.push(e)),onError:e=>this.logger.error(`SSR 渲染失败: ${e?.message??e}`,"rollup")})]}}export{A as default};
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bundlekit/bundler-rollup",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A rollup bundler for @bundlekit/service",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"cjs": "./dist/index.cjs",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.cjs",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"package.json"
|
|
19
|
+
],
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@babel/preset-env": "^7.24.0",
|
|
22
|
+
"@babel/preset-typescript": "^7.24.0",
|
|
23
|
+
"@rollup/plugin-babel": "^6.0.4",
|
|
24
|
+
"@rollup/plugin-commonjs": "^25.0.7",
|
|
25
|
+
"@rollup/plugin-image": "^3.0.3",
|
|
26
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
27
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
28
|
+
"@rollup/plugin-replace": "^6.0.0",
|
|
29
|
+
"@rollup/plugin-typescript": "^12.1.2",
|
|
30
|
+
"rollup": "^4.40.0",
|
|
31
|
+
"rollup-plugin-postcss": "^4.0.2",
|
|
32
|
+
"schema-utils": "^4.3.0",
|
|
33
|
+
"@bundlekit/shared-utils": "0.0.1"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
37
|
+
"rollup": "^4.40.0",
|
|
38
|
+
"tslib": "^2.6.2"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"rollup",
|
|
42
|
+
"bundlekit-budnler-rollup",
|
|
43
|
+
"bundlekit-bundler",
|
|
44
|
+
"bundlekit"
|
|
45
|
+
],
|
|
46
|
+
"author": "harhao@163.com",
|
|
47
|
+
"license": "ISC",
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"registry": "https://registry.npmjs.org/",
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">= 18.0.0"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"clean": "rimraf ./dist",
|
|
57
|
+
"rollup:build": "pnpm run clean && rollup -c ./scripts/rollup.config.js"
|
|
58
|
+
}
|
|
59
|
+
}
|