@rspnseapp/dev-inspector 0.1.0 → 0.2.0

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.
@@ -0,0 +1,59 @@
1
+ import { Compiler } from 'webpack';
2
+
3
+ interface BreadcrumbItem {
4
+ label: string;
5
+ index: number;
6
+ }
7
+ interface InspectedElement {
8
+ selector: string;
9
+ tagName: string;
10
+ classList: string[];
11
+ id: string | null;
12
+ computedStyles: Record<string, string>;
13
+ }
14
+ interface StyleEntry {
15
+ type: 'inline' | 'external';
16
+ index?: number;
17
+ href?: string;
18
+ css: string | null;
19
+ error?: string;
20
+ }
21
+ interface RspnseInspectorOptions {
22
+ /**
23
+ * Enable/disable the inspector. Defaults to true in development.
24
+ */
25
+ enabled?: boolean;
26
+ /**
27
+ * Trusted origins that can communicate with the inspector.
28
+ * Defaults to ['https://rspnse.net', 'http://localhost']
29
+ */
30
+ trustedOrigins?: string[];
31
+ }
32
+
33
+ /**
34
+ * Webpack plugin that injects the Rspnse inspector script into dev server pages.
35
+ * This enables inspect functionality from rspnse.net without a browser extension.
36
+ *
37
+ * @example
38
+ * ```ts
39
+ * // webpack.config.js (ESM)
40
+ * import { RspnseInspectorPlugin } from '@rspnseapp/dev-inspector/webpack';
41
+ *
42
+ * export default {
43
+ * plugins: [new RspnseInspectorPlugin()]
44
+ * }
45
+ * ```
46
+ */
47
+ declare class RspnseInspectorPlugin {
48
+ private options;
49
+ private inspectorScript;
50
+ constructor(options?: RspnseInspectorOptions);
51
+ private getInspectorScript;
52
+ apply(compiler: Compiler): void;
53
+ }
54
+ /**
55
+ * Factory function for creating the plugin (alternative to class instantiation)
56
+ */
57
+ declare function rspnseInspector(options?: RspnseInspectorOptions): RspnseInspectorPlugin;
58
+
59
+ export { type BreadcrumbItem, type InspectedElement, type RspnseInspectorOptions, RspnseInspectorPlugin, type StyleEntry, rspnseInspector };
@@ -0,0 +1,105 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/webpack-plugin.ts
9
+ import { readFileSync } from "fs";
10
+ import { resolve, dirname } from "path";
11
+ import { fileURLToPath } from "url";
12
+ var PLUGIN_NAME = "RspnseInspectorPlugin";
13
+ var INSPECTOR_PATH = "/__rspnse-inspector__/inspector.js";
14
+ var __dirname = dirname(fileURLToPath(import.meta.url));
15
+ var RspnseInspectorPlugin = class {
16
+ constructor(options = {}) {
17
+ this.inspectorScript = null;
18
+ this.options = {
19
+ enabled: true,
20
+ ...options
21
+ };
22
+ }
23
+ getInspectorScript() {
24
+ if (this.inspectorScript) return this.inspectorScript;
25
+ try {
26
+ const scriptPath = resolve(__dirname, "index.inspector.js");
27
+ this.inspectorScript = readFileSync(scriptPath, "utf-8");
28
+ } catch {
29
+ console.warn(
30
+ `[${PLUGIN_NAME}] Could not load inspector script from ${__dirname}.`
31
+ );
32
+ this.inspectorScript = "// Inspector script not found";
33
+ }
34
+ return this.inspectorScript;
35
+ }
36
+ apply(compiler) {
37
+ if (!this.options.enabled) return;
38
+ if (compiler.options.mode !== "development") return;
39
+ const { trustedOrigins } = this.options;
40
+ compiler.hooks.afterEnvironment.tap(PLUGIN_NAME, () => {
41
+ const devServer = compiler.options.devServer;
42
+ if (!devServer) return;
43
+ const originalSetupMiddlewares = devServer.setupMiddlewares;
44
+ devServer.setupMiddlewares = (middlewares, devServerInstance) => {
45
+ middlewares.unshift({
46
+ name: PLUGIN_NAME,
47
+ path: INSPECTOR_PATH,
48
+ middleware: (_req, res) => {
49
+ res.setHeader("Content-Type", "application/javascript");
50
+ res.setHeader("Cache-Control", "no-cache");
51
+ let script = this.getInspectorScript();
52
+ if (trustedOrigins && trustedOrigins.length > 0) {
53
+ const originsArray = JSON.stringify(trustedOrigins);
54
+ script = `window.__RSPNSE_TRUSTED_ORIGINS__ = ${originsArray};
55
+ ${script}`;
56
+ }
57
+ res.end(script);
58
+ }
59
+ });
60
+ if (originalSetupMiddlewares) {
61
+ return originalSetupMiddlewares(middlewares, devServerInstance);
62
+ }
63
+ return middlewares;
64
+ };
65
+ });
66
+ compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
67
+ compilation.hooks.processAssets.tap(
68
+ {
69
+ name: PLUGIN_NAME,
70
+ // Run after HTML has been generated
71
+ stage: 1e3
72
+ },
73
+ (assets) => {
74
+ const scriptTag = `<script src="${INSPECTOR_PATH}" defer></script>`;
75
+ for (const name of Object.keys(assets)) {
76
+ if (name.endsWith(".html")) {
77
+ const asset = assets[name];
78
+ let html = asset.source().toString();
79
+ if (html.includes(INSPECTOR_PATH)) continue;
80
+ if (html.includes("</head>")) {
81
+ html = html.replace("</head>", `${scriptTag}
82
+ </head>`);
83
+ } else if (html.includes("<body")) {
84
+ html = html.replace(/<body([^>]*)>/, `<body$1>
85
+ ${scriptTag}`);
86
+ } else {
87
+ html = scriptTag + "\n" + html;
88
+ }
89
+ const webpack = __require("webpack");
90
+ compilation.updateAsset(name, new webpack.sources.RawSource(html));
91
+ }
92
+ }
93
+ }
94
+ );
95
+ });
96
+ }
97
+ };
98
+ function rspnseInspector(options = {}) {
99
+ return new RspnseInspectorPlugin(options);
100
+ }
101
+ export {
102
+ RspnseInspectorPlugin,
103
+ rspnseInspector
104
+ };
105
+ //# sourceMappingURL=webpack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/webpack-plugin.ts"],"sourcesContent":["import type { Compiler } from 'webpack';\nimport { readFileSync } from 'fs';\nimport { resolve, dirname } from 'path';\nimport { fileURLToPath } from 'url';\nimport type { RspnseInspectorOptions } from './types';\n\nconst PLUGIN_NAME = 'RspnseInspectorPlugin';\nconst INSPECTOR_PATH = '/__rspnse-inspector__/inspector.js';\n\n// Get the directory of this module (ESM)\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Webpack plugin that injects the Rspnse inspector script into dev server pages.\n * This enables inspect functionality from rspnse.net without a browser extension.\n *\n * @example\n * ```ts\n * // webpack.config.js (ESM)\n * import { RspnseInspectorPlugin } from '@rspnseapp/dev-inspector/webpack';\n *\n * export default {\n * plugins: [new RspnseInspectorPlugin()]\n * }\n * ```\n */\nexport class RspnseInspectorPlugin {\n private options: Required<Pick<RspnseInspectorOptions, 'enabled'>> &\n RspnseInspectorOptions;\n private inspectorScript: string | null = null;\n\n constructor(options: RspnseInspectorOptions = {}) {\n this.options = {\n enabled: true,\n ...options,\n };\n }\n\n private getInspectorScript(): string {\n if (this.inspectorScript) return this.inspectorScript;\n\n try {\n // Load the bundled inspector script from dist\n const scriptPath = resolve(__dirname, 'index.inspector.js');\n this.inspectorScript = readFileSync(scriptPath, 'utf-8');\n } catch {\n console.warn(\n `[${PLUGIN_NAME}] Could not load inspector script from ${__dirname}.`\n );\n this.inspectorScript = '// Inspector script not found';\n }\n\n return this.inspectorScript;\n }\n\n apply(compiler: Compiler): void {\n if (!this.options.enabled) return;\n\n // Only apply in development mode\n if (compiler.options.mode !== 'development') return;\n\n const { trustedOrigins } = this.options;\n\n // Add middleware to serve the inspector script via devServer\n compiler.hooks.afterEnvironment.tap(PLUGIN_NAME, () => {\n const devServer = compiler.options.devServer as\n | {\n setupMiddlewares?: (\n middlewares: Array<{\n name: string;\n path: string;\n middleware: (\n req: unknown,\n res: { setHeader: (k: string, v: string) => void; end: (s: string) => void }\n ) => void;\n }>,\n devServer: unknown\n ) => unknown[];\n }\n | undefined;\n\n if (!devServer) return;\n\n // Store original setupMiddlewares if it exists\n const originalSetupMiddlewares = devServer.setupMiddlewares;\n\n devServer.setupMiddlewares = (middlewares, devServerInstance) => {\n // Add our middleware first\n middlewares.unshift({\n name: PLUGIN_NAME,\n path: INSPECTOR_PATH,\n middleware: (_req, res) => {\n res.setHeader('Content-Type', 'application/javascript');\n res.setHeader('Cache-Control', 'no-cache');\n\n let script = this.getInspectorScript();\n\n // If custom trusted origins are provided, inject them\n if (trustedOrigins && trustedOrigins.length > 0) {\n const originsArray = JSON.stringify(trustedOrigins);\n script = `window.__RSPNSE_TRUSTED_ORIGINS__ = ${originsArray};\\n${script}`;\n }\n\n res.end(script);\n },\n });\n\n // Call original setupMiddlewares if it exists\n if (originalSetupMiddlewares) {\n return originalSetupMiddlewares(middlewares, devServerInstance) as typeof middlewares;\n }\n\n return middlewares;\n };\n });\n\n // Inject script tag into HTML assets\n compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {\n compilation.hooks.processAssets.tap(\n {\n name: PLUGIN_NAME,\n // Run after HTML has been generated\n stage: 1000,\n },\n (assets) => {\n const scriptTag = `<script src=\"${INSPECTOR_PATH}\" defer></script>`;\n\n for (const name of Object.keys(assets)) {\n if (name.endsWith('.html')) {\n const asset = assets[name];\n let html = asset.source().toString();\n\n // Don't inject twice\n if (html.includes(INSPECTOR_PATH)) continue;\n\n if (html.includes('</head>')) {\n html = html.replace('</head>', `${scriptTag}\\n</head>`);\n } else if (html.includes('<body')) {\n html = html.replace(/<body([^>]*)>/, `<body$1>\\n${scriptTag}`);\n } else {\n html = scriptTag + '\\n' + html;\n }\n\n // Update the asset - use webpack's sources API\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const webpack = require('webpack') as typeof import('webpack');\n compilation.updateAsset(name, new webpack.sources.RawSource(html));\n }\n }\n }\n );\n });\n }\n}\n\n/**\n * Factory function for creating the plugin (alternative to class instantiation)\n */\nexport function rspnseInspector(\n options: RspnseInspectorOptions = {}\n): RspnseInspectorPlugin {\n return new RspnseInspectorPlugin(options);\n}\n"],"mappings":";;;;;;;;AACA,SAAS,oBAAoB;AAC7B,SAAS,SAAS,eAAe;AACjC,SAAS,qBAAqB;AAG9B,IAAM,cAAc;AACpB,IAAM,iBAAiB;AAGvB,IAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AAgBjD,IAAM,wBAAN,MAA4B;AAAA,EAKjC,YAAY,UAAkC,CAAC,GAAG;AAFlD,SAAQ,kBAAiC;AAGvC,SAAK,UAAU;AAAA,MACb,SAAS;AAAA,MACT,GAAG;AAAA,IACL;AAAA,EACF;AAAA,EAEQ,qBAA6B;AACnC,QAAI,KAAK,gBAAiB,QAAO,KAAK;AAEtC,QAAI;AAEF,YAAM,aAAa,QAAQ,WAAW,oBAAoB;AAC1D,WAAK,kBAAkB,aAAa,YAAY,OAAO;AAAA,IACzD,QAAQ;AACN,cAAQ;AAAA,QACN,IAAI,WAAW,0CAA0C,SAAS;AAAA,MACpE;AACA,WAAK,kBAAkB;AAAA,IACzB;AAEA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,UAA0B;AAC9B,QAAI,CAAC,KAAK,QAAQ,QAAS;AAG3B,QAAI,SAAS,QAAQ,SAAS,cAAe;AAE7C,UAAM,EAAE,eAAe,IAAI,KAAK;AAGhC,aAAS,MAAM,iBAAiB,IAAI,aAAa,MAAM;AACrD,YAAM,YAAY,SAAS,QAAQ;AAgBnC,UAAI,CAAC,UAAW;AAGhB,YAAM,2BAA2B,UAAU;AAE3C,gBAAU,mBAAmB,CAAC,aAAa,sBAAsB;AAE/D,oBAAY,QAAQ;AAAA,UAClB,MAAM;AAAA,UACN,MAAM;AAAA,UACN,YAAY,CAAC,MAAM,QAAQ;AACzB,gBAAI,UAAU,gBAAgB,wBAAwB;AACtD,gBAAI,UAAU,iBAAiB,UAAU;AAEzC,gBAAI,SAAS,KAAK,mBAAmB;AAGrC,gBAAI,kBAAkB,eAAe,SAAS,GAAG;AAC/C,oBAAM,eAAe,KAAK,UAAU,cAAc;AAClD,uBAAS,uCAAuC,YAAY;AAAA,EAAM,MAAM;AAAA,YAC1E;AAEA,gBAAI,IAAI,MAAM;AAAA,UAChB;AAAA,QACF,CAAC;AAGD,YAAI,0BAA0B;AAC5B,iBAAO,yBAAyB,aAAa,iBAAiB;AAAA,QAChE;AAEA,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAGD,aAAS,MAAM,YAAY,IAAI,aAAa,CAAC,gBAAgB;AAC3D,kBAAY,MAAM,cAAc;AAAA,QAC9B;AAAA,UACE,MAAM;AAAA;AAAA,UAEN,OAAO;AAAA,QACT;AAAA,QACA,CAAC,WAAW;AACV,gBAAM,YAAY,gBAAgB,cAAc;AAEhD,qBAAW,QAAQ,OAAO,KAAK,MAAM,GAAG;AACtC,gBAAI,KAAK,SAAS,OAAO,GAAG;AAC1B,oBAAM,QAAQ,OAAO,IAAI;AACzB,kBAAI,OAAO,MAAM,OAAO,EAAE,SAAS;AAGnC,kBAAI,KAAK,SAAS,cAAc,EAAG;AAEnC,kBAAI,KAAK,SAAS,SAAS,GAAG;AAC5B,uBAAO,KAAK,QAAQ,WAAW,GAAG,SAAS;AAAA,QAAW;AAAA,cACxD,WAAW,KAAK,SAAS,OAAO,GAAG;AACjC,uBAAO,KAAK,QAAQ,iBAAiB;AAAA,EAAa,SAAS,EAAE;AAAA,cAC/D,OAAO;AACL,uBAAO,YAAY,OAAO;AAAA,cAC5B;AAIA,oBAAM,UAAU,UAAQ,SAAS;AACjC,0BAAY,YAAY,MAAM,IAAI,QAAQ,QAAQ,UAAU,IAAI,CAAC;AAAA,YACnE;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAKO,SAAS,gBACd,UAAkC,CAAC,GACZ;AACvB,SAAO,IAAI,sBAAsB,OAAO;AAC1C;","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rspnseapp/dev-inspector",
3
- "version": "0.1.0",
4
- "description": "Dev server plugin for Rspnse inspect functionality",
3
+ "version": "0.2.0",
4
+ "description": "Dev server plugins for Rspnse inspect functionality (Vite & Webpack)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
@@ -10,6 +10,10 @@
10
10
  ".": {
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js"
13
+ },
14
+ "./webpack": {
15
+ "types": "./dist/webpack.d.ts",
16
+ "import": "./dist/webpack.js"
13
17
  }
14
18
  },
15
19
  "files": [
@@ -24,6 +28,7 @@
24
28
  },
25
29
  "keywords": [
26
30
  "vite-plugin",
31
+ "webpack-plugin",
27
32
  "rspnse",
28
33
  "responsive",
29
34
  "inspect",
@@ -38,16 +43,22 @@
38
43
  "directory": "packages/dev-inspector"
39
44
  },
40
45
  "peerDependencies": {
41
- "vite": ">=4.0.0"
46
+ "vite": ">=4.0.0",
47
+ "webpack": ">=5.0.0"
42
48
  },
43
49
  "peerDependenciesMeta": {
44
50
  "vite": {
45
51
  "optional": true
52
+ },
53
+ "webpack": {
54
+ "optional": true
46
55
  }
47
56
  },
48
57
  "devDependencies": {
58
+ "@types/webpack": "^5.28.0",
49
59
  "tsup": "^8.0.0",
50
60
  "typescript": "^5.0.0",
51
- "vite": "^6.0.0"
61
+ "vite": "^6.0.0",
62
+ "webpack": "^5.0.0"
52
63
  }
53
64
  }