blogger-plugin 0.0.0 → 0.0.2
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/LICENSE.md +21 -0
- package/README.md +150 -1
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/vite.cjs +399 -0
- package/dist/vite.cjs.map +1 -0
- package/dist/vite.d.cts +13 -0
- package/dist/vite.d.ts +13 -0
- package/dist/vite.js +399 -0
- package/dist/vite.js.map +1 -0
- package/package.json +63 -3
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Deo Kumar <https://github.com/kumardeo>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1 +1,150 @@
|
|
|
1
|
-
|
|
1
|
+
# Blogger Plugin
|
|
2
|
+
|
|
3
|
+
A plugin that allows you to use modern frontend frameworks inside a Blogger template.
|
|
4
|
+
|
|
5
|
+
## ✨ Features
|
|
6
|
+
|
|
7
|
+
- ✅ Supports **all major frontend frameworks** supported by Vite — including **React, Vue, Svelte, Solid**, and more.
|
|
8
|
+
- 🔄 Enables **local development** by proxying unhandled requests to a Blogger blog.
|
|
9
|
+
- 🧩 Works seamlessly with Vite’s dev server and build system.
|
|
10
|
+
|
|
11
|
+
## 📦 Installation
|
|
12
|
+
|
|
13
|
+
```shell
|
|
14
|
+
npm install blogger-plugin
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## ⚡ Usage with Vite
|
|
18
|
+
|
|
19
|
+
**1**. **Create a new Blogger blog** for development and preview purposes.
|
|
20
|
+
This blog will be used as a proxy target for unhandled requests during local development.
|
|
21
|
+
|
|
22
|
+
**2**. **Create a new Vite project** using your preferred frontend framework (React, Vue, Svelte, etc.):
|
|
23
|
+
|
|
24
|
+
```shell
|
|
25
|
+
npm create vite
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**3**. **Create a Blogger XML template file**
|
|
29
|
+
Inside your project's `src` directory, create a new file named `template.xml`.
|
|
30
|
+
|
|
31
|
+
**Head section**
|
|
32
|
+
|
|
33
|
+
Add the following code inside the `<head>` section of your Blogger template:
|
|
34
|
+
|
|
35
|
+
```xml
|
|
36
|
+
<b:if cond='data:blog.view contains "-DevServer" or data:blog.view contains "-PreviewServer"'>
|
|
37
|
+
<!--blogger-plugin:head:begin--><!--blogger-plugin:head:end-->
|
|
38
|
+
|
|
39
|
+
<b:else/>
|
|
40
|
+
<b:comment><!--blogger-plugin:head:begin--></b:comment><b:comment><!--blogger-plugin:head:end--></b:comment>
|
|
41
|
+
</b:if>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This snippet ensures that **development and preview HTML tags** are correctly injected into the HTML content from the proxied blog, while **production HTML** tags are injected into the XML content.
|
|
45
|
+
|
|
46
|
+
**Body section**
|
|
47
|
+
|
|
48
|
+
Inside the `<body>`, add a root container for your frontend app:
|
|
49
|
+
|
|
50
|
+
```xml
|
|
51
|
+
<div id='root'></div>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
or, depending on your framework:
|
|
55
|
+
|
|
56
|
+
```xml
|
|
57
|
+
<div id='app'></div>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This element will serve as the mounting point for your frontend framework.
|
|
61
|
+
|
|
62
|
+
**4**. **Add the template to your proxy Blogger blog**
|
|
63
|
+
Open your proxy blog (the one used for local development), go to **Dashboard** → **Theme** → **Edit HTML**, and replace its contents with the template from your project's `template.xml` file.
|
|
64
|
+
|
|
65
|
+
This ensures that the Blogger Plugin can inject your app's assets during development and preview phases.
|
|
66
|
+
|
|
67
|
+
**5**. **Add the Blogger plugin** to your Vite configuration file (i.e. `vite.config.ts`, `vite.config.js`, etc.):
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import react from "@vitejs/plugin-react-swc";
|
|
71
|
+
import blogger from "blogger-plugin/vite";
|
|
72
|
+
import { defineConfig } from "vite";
|
|
73
|
+
|
|
74
|
+
// https://vite.dev/config/
|
|
75
|
+
export default defineConfig({
|
|
76
|
+
plugins: [
|
|
77
|
+
react(),
|
|
78
|
+
blogger({
|
|
79
|
+
// Unhandled requests will be proxied to this Blogger blog
|
|
80
|
+
proxyBlog: "https://example.blogspot.com",
|
|
81
|
+
|
|
82
|
+
// (optional) Custom entry file path
|
|
83
|
+
// Defaults to one of: src/{index|main}.{tsx|ts|jsx|js}
|
|
84
|
+
// entry: "src/my-entry.ts",
|
|
85
|
+
|
|
86
|
+
// (optional) Custom Blogger XML template path
|
|
87
|
+
// Defaults to one of: src/{template|theme}.xml
|
|
88
|
+
// template: "src/my-template.xml",
|
|
89
|
+
}),
|
|
90
|
+
],
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**6**. **Start the development server**
|
|
95
|
+
|
|
96
|
+
```shell
|
|
97
|
+
npm run dev
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**7**. **Modify the template during development**
|
|
101
|
+
|
|
102
|
+
During development, you can **freely edit the XML** directly from the Blogger dashboard.
|
|
103
|
+
The local dev server proxies all requests to your live blog and dynamically injects the latest HTML output, so you can preview live updates instantly.
|
|
104
|
+
|
|
105
|
+
> [!TIP]
|
|
106
|
+
> Once you're satisfied with the final template, copy the **dashboard XML** back into your project's `template.xml` before running your production build.
|
|
107
|
+
|
|
108
|
+
**8**. **Build for production**
|
|
109
|
+
When you’re ready to build, run:
|
|
110
|
+
|
|
111
|
+
```shell
|
|
112
|
+
npm run build
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
After the build completes, a `template.xml` file will be generated inside your project's **output directory** (`outDir`), containing all **injected asset tags** (CSS, JS, and other resources) required by your framework.
|
|
116
|
+
|
|
117
|
+
You can then upload this generated XML to your main Blogger blog via **Theme** → **Edit HTML**.
|
|
118
|
+
|
|
119
|
+
## ☁️ Hosting Assets on a CDN
|
|
120
|
+
|
|
121
|
+
Since **Blogger doesn't allow** hosting custom static assets, you'll need to serve your built files (JS, CSS, images) from a third-party CDN, such as [jsDelivr](https://www.jsdelivr.com/), GitHub Pages, or Cloudflare Workers Static Assets.
|
|
122
|
+
|
|
123
|
+
To configure your asset URLs, specify a `base` path in your Vite config — for example:
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
export default defineConfig({
|
|
127
|
+
base: process.env.VITE_BASE ?? "/",
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Then, set the environment variable when building for production:
|
|
132
|
+
|
|
133
|
+
```shell
|
|
134
|
+
VITE_BASE="https://cdn.jsdelivr.net/gh/username/repo@version/" pnpm run build
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
This ensures all injected asset tags inside the generated `template.xml` point to your CDN-hosted files.
|
|
138
|
+
|
|
139
|
+
## 📌 Example
|
|
140
|
+
|
|
141
|
+
A fully working example using **React**, **jsDelivr**, and **GitHub Actions** is available in this GitHub repository:
|
|
142
|
+
|
|
143
|
+
https://github.com/kumardeo/react-blogger-template
|
|
144
|
+
|
|
145
|
+
The GitHub Actions workflow automatically:
|
|
146
|
+
|
|
147
|
+
1. Runs on commits to the `release` branch.
|
|
148
|
+
2. Builds the React app and generates `dist/template.xml`.
|
|
149
|
+
3. Commits all built assets and `template.xml` to the `static` branch.
|
|
150
|
+
4. Creates a new tag for jsDelivr so assets can be served via CDN.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/blogger-plugin/blogger-plugin/packages/blogger-plugin/dist/index.cjs"],"names":[],"mappings":"AAAA","file":"/home/runner/work/blogger-plugin/blogger-plugin/packages/blogger-plugin/dist/index.cjs"}
|
package/dist/index.d.cts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/vite.cjs
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/vite.ts
|
|
2
|
+
var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs);
|
|
3
|
+
var _path = require('path'); var _path2 = _interopRequireDefault(_path);
|
|
4
|
+
var _stream = require('stream');
|
|
5
|
+
|
|
6
|
+
// src/schema.ts
|
|
7
|
+
var _zod = require('zod');
|
|
8
|
+
var BloggerPluginOptionsSchema = _zod.z.object({
|
|
9
|
+
entry: _zod.z.string().optional(),
|
|
10
|
+
template: _zod.z.string().optional(),
|
|
11
|
+
proxyBlog: _zod.z.url()
|
|
12
|
+
}).strict();
|
|
13
|
+
|
|
14
|
+
// src/utils.ts
|
|
15
|
+
function escapeHtml(str) {
|
|
16
|
+
if (str === "") return "";
|
|
17
|
+
return str.replace(/[&<>"'`]/g, (ch) => {
|
|
18
|
+
switch (ch) {
|
|
19
|
+
case "&":
|
|
20
|
+
return "&";
|
|
21
|
+
case "<":
|
|
22
|
+
return "<";
|
|
23
|
+
case ">":
|
|
24
|
+
return ">";
|
|
25
|
+
case '"':
|
|
26
|
+
return """;
|
|
27
|
+
case "'":
|
|
28
|
+
return "'";
|
|
29
|
+
case "`":
|
|
30
|
+
return "`";
|
|
31
|
+
default:
|
|
32
|
+
return ch;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function escapeRegex(str) {
|
|
37
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
38
|
+
}
|
|
39
|
+
function toWebHeaders(httpHeaders) {
|
|
40
|
+
const headers = new Headers();
|
|
41
|
+
for (const [name, value] of Object.entries(httpHeaders)) {
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
for (const item of value) {
|
|
44
|
+
headers.append(name, item);
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
headers.set(name, String(value != null ? value : ""));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return headers;
|
|
51
|
+
}
|
|
52
|
+
function replaceBloggerPluginHeadComment(input, replacement, bcomment = false) {
|
|
53
|
+
if (bcomment) {
|
|
54
|
+
return input.replace(
|
|
55
|
+
/<b:comment><!--blogger-plugin:head:begin--><\/b:comment>[\s\S]*?<b:comment><!--blogger-plugin:head:end--><\/b:comment>/,
|
|
56
|
+
`<b:comment><!--blogger-plugin:head:begin--></b:comment>${replacement}<b:comment><!--blogger-plugin:head:end--></b:comment>`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return input.replace(
|
|
60
|
+
/<!--blogger-plugin:head:begin-->[\s\S]*?<!--blogger-plugin:head:end-->/,
|
|
61
|
+
`<!--blogger-plugin:head:begin-->${replacement}<!--blogger-plugin:head:end-->`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
function getBloggerPluginHeadComment(input, bcomment = false) {
|
|
65
|
+
var _a, _b, _c, _d;
|
|
66
|
+
if (bcomment) {
|
|
67
|
+
return (_b = (_a = input.match(/<b:comment><!--blogger-plugin:head:begin--><\/b:comment>([\s\S]*?)<b:comment><!--blogger-plugin:head:end--><\/b:comment>/)) == null ? void 0 : _a[1]) != null ? _b : null;
|
|
68
|
+
}
|
|
69
|
+
return (_d = (_c = input.match(/<!--blogger-plugin:head:begin-->([\s\S]*?)<!--blogger-plugin:head:end-->/)) == null ? void 0 : _c[1]) != null ? _d : null;
|
|
70
|
+
}
|
|
71
|
+
function replaceHost(input, oldHost, newHost, newProtocol) {
|
|
72
|
+
return input.replace(
|
|
73
|
+
new RegExp(`(https?:)?(\\/\\/|\\\\/\\\\/)${escapeRegex(oldHost)}`, "g"),
|
|
74
|
+
(_, protocol, slash) => `${protocol ? newProtocol != null ? newProtocol : protocol : ""}${slash != null ? slash : ""}${newHost}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
function errorHtml(reqUrl) {
|
|
78
|
+
return `<!DOCTYPE html>
|
|
79
|
+
<html>
|
|
80
|
+
|
|
81
|
+
<head>
|
|
82
|
+
<meta charset='UTF-8'/>
|
|
83
|
+
<meta content='width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=5, user-scalable=yes' name='viewport'/>
|
|
84
|
+
<title>500 Internal Server Error</title>
|
|
85
|
+
<link rel='icon' href='data:,' />
|
|
86
|
+
<style>
|
|
87
|
+
*, ::before, ::after {
|
|
88
|
+
box-sizing: border-box;
|
|
89
|
+
}
|
|
90
|
+
body {
|
|
91
|
+
min-height: 100svh;
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
align-items: center;
|
|
95
|
+
justify-content: center;
|
|
96
|
+
margin: 0;
|
|
97
|
+
padding: 20px;
|
|
98
|
+
background-color: #f5f5f5;
|
|
99
|
+
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", Segoe UI Symbol, "Noto Color Emoji";
|
|
100
|
+
}
|
|
101
|
+
.card {
|
|
102
|
+
padding: 24px;
|
|
103
|
+
background-color: #ffffff;
|
|
104
|
+
border: 1px solid #e5e5e5;
|
|
105
|
+
max-width: 448px;
|
|
106
|
+
border-radius: 14px;
|
|
107
|
+
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
|
|
108
|
+
display: flex;
|
|
109
|
+
flex-direction: column;
|
|
110
|
+
gap: 24px;
|
|
111
|
+
}
|
|
112
|
+
.card-content {
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
gap: 6px;
|
|
116
|
+
}
|
|
117
|
+
.card-title {
|
|
118
|
+
font-weight: 600;
|
|
119
|
+
}
|
|
120
|
+
.card-description {
|
|
121
|
+
font-size: 14px;
|
|
122
|
+
opacity: 0.85;
|
|
123
|
+
}
|
|
124
|
+
.card-footer {
|
|
125
|
+
display: flex;
|
|
126
|
+
align-items: center;
|
|
127
|
+
}
|
|
128
|
+
.button {
|
|
129
|
+
display: inline-flex;
|
|
130
|
+
white-space: nowrap;
|
|
131
|
+
align-items: center;
|
|
132
|
+
justify-content: center;
|
|
133
|
+
gap: 8px;
|
|
134
|
+
padding: 8px 16px;
|
|
135
|
+
font-weight: 500;
|
|
136
|
+
background-color: #171717;
|
|
137
|
+
outline: none;
|
|
138
|
+
border: none;
|
|
139
|
+
color: #ffffff;
|
|
140
|
+
border-radius: 8px;
|
|
141
|
+
min-height: 36px;
|
|
142
|
+
}
|
|
143
|
+
.button:hover {
|
|
144
|
+
opacity: 0.9;
|
|
145
|
+
}
|
|
146
|
+
.button svg {
|
|
147
|
+
wiheadersdth: 16px;
|
|
148
|
+
height: 16px;
|
|
149
|
+
flex-shrink: 0;
|
|
150
|
+
}
|
|
151
|
+
.card-footer .button {
|
|
152
|
+
flex-grow: 1;
|
|
153
|
+
}
|
|
154
|
+
</style>
|
|
155
|
+
</head>
|
|
156
|
+
|
|
157
|
+
<body>
|
|
158
|
+
<div class='card'>
|
|
159
|
+
<div class='card-content'>
|
|
160
|
+
<div class='card-title'>500 Internal Server Error</div>
|
|
161
|
+
<div class='card-description'>Failed to fetch: ${escapeHtml(reqUrl)}</div>
|
|
162
|
+
</div>
|
|
163
|
+
<div class='card-footer'>
|
|
164
|
+
<button class='button' type='button'>
|
|
165
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-refresh-ccw" aria-hidden="true"><path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path><path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"></path><path d="M16 16h5v5"></path></svg>
|
|
166
|
+
Reload
|
|
167
|
+
</button>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
<script>
|
|
171
|
+
const button = document.getElementsByTagName('button')[0];
|
|
172
|
+
button.addEventListener('click', () => {
|
|
173
|
+
window.location.reload();
|
|
174
|
+
});
|
|
175
|
+
</script>
|
|
176
|
+
</body>
|
|
177
|
+
|
|
178
|
+
</html>`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/vite.ts
|
|
182
|
+
var DEFAULT_ENTRIES = ["index.tsx", "index.ts", "index.jsx", "index.js", "main.tsx", "main.ts", "main.jsx", "main.js"];
|
|
183
|
+
var DEFAULT_TEMPLATES = ["template.xml", "theme.xml"];
|
|
184
|
+
function createPluginContext(userOptions) {
|
|
185
|
+
return {
|
|
186
|
+
viteConfig: void 0,
|
|
187
|
+
entry: void 0,
|
|
188
|
+
template: void 0,
|
|
189
|
+
options: BloggerPluginOptionsSchema.parse(userOptions)
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function isViteDevServer(server) {
|
|
193
|
+
return "hot" in server && "transformRequest" in server && "transformIndexHtml" in server;
|
|
194
|
+
}
|
|
195
|
+
function useServerMiddleware(server, ctx, _this) {
|
|
196
|
+
return () => {
|
|
197
|
+
var _a;
|
|
198
|
+
(_a = server.httpServer) == null ? void 0 : _a.once("listening", () => {
|
|
199
|
+
setTimeout(() => {
|
|
200
|
+
_this.info(`Unhandled requests will be proxied to ${ctx.options.proxyBlog}`);
|
|
201
|
+
}, 0);
|
|
202
|
+
});
|
|
203
|
+
server.middlewares.use(async (req, res, next) => {
|
|
204
|
+
var _a2;
|
|
205
|
+
if (!req.url || !req.originalUrl) {
|
|
206
|
+
next();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const start = Date.now();
|
|
210
|
+
const proxyUrl = new URL(req.originalUrl, ctx.options.proxyBlog);
|
|
211
|
+
const viewParam = proxyUrl.searchParams.get("view");
|
|
212
|
+
proxyUrl.searchParams.set("view", `${isViteDevServer(server) ? "-DevServer" : "-PreviewServer"}${(viewParam == null ? void 0 : viewParam.startsWith("-")) ? viewParam : ""}`);
|
|
213
|
+
const proxyRequest = new Request(proxyUrl, {
|
|
214
|
+
method: req.method,
|
|
215
|
+
headers: toWebHeaders(req.headers),
|
|
216
|
+
body: ["GET", "HEAD"].includes((_a2 = req.method) != null ? _a2 : "") ? void 0 : _stream.Readable.toWeb(req),
|
|
217
|
+
redirect: "manual"
|
|
218
|
+
});
|
|
219
|
+
const proxyResponse = await fetch(proxyRequest).catch((error) => {
|
|
220
|
+
if (error instanceof Error) {
|
|
221
|
+
_this.warn({
|
|
222
|
+
message: `${error.name}: ${error.message}`,
|
|
223
|
+
cause: error.cause,
|
|
224
|
+
stack: error.stack
|
|
225
|
+
});
|
|
226
|
+
} else {
|
|
227
|
+
_this.warn("Fetch failed");
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
});
|
|
231
|
+
if (proxyResponse) {
|
|
232
|
+
const requestProtocol = `${req.headers["x-forwarded-proto"] || (req.socket && "encrypted" in req.socket && req.socket.encrypted ? "https" : "http")}:`;
|
|
233
|
+
const requestHost = req.headers["x-forwarded-host"] || req.headers.host;
|
|
234
|
+
res.statusCode = proxyResponse.status;
|
|
235
|
+
res.statusMessage = proxyResponse.statusText;
|
|
236
|
+
proxyResponse.headers.forEach((value, key) => {
|
|
237
|
+
var _a3;
|
|
238
|
+
if (key === "location") {
|
|
239
|
+
const redirectUrl = new URL(value, requestHost ? `${requestProtocol}//${requestHost}${req.originalUrl}` : proxyUrl.href);
|
|
240
|
+
if (requestHost && redirectUrl.host === requestHost || redirectUrl.host === proxyUrl.host) {
|
|
241
|
+
if (requestHost && requestProtocol) {
|
|
242
|
+
redirectUrl.host = requestHost;
|
|
243
|
+
redirectUrl.protocol = requestProtocol;
|
|
244
|
+
}
|
|
245
|
+
const viewParam2 = (_a3 = redirectUrl.searchParams.get("view")) == null ? void 0 : _a3.replaceAll("-DevServer", "").replaceAll("-PreviewServer", "");
|
|
246
|
+
if (viewParam2) {
|
|
247
|
+
redirectUrl.searchParams.set("view", viewParam2);
|
|
248
|
+
} else {
|
|
249
|
+
redirectUrl.searchParams.delete("view");
|
|
250
|
+
}
|
|
251
|
+
res.setHeader(key, redirectUrl.pathname + redirectUrl.search + redirectUrl.hash);
|
|
252
|
+
} else {
|
|
253
|
+
res.setHeader(key, redirectUrl.href);
|
|
254
|
+
}
|
|
255
|
+
} else if (["content-type", "x-robots-tag", "date", "location"].includes(key)) {
|
|
256
|
+
res.setHeader(key, value);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
const contentType = proxyResponse.headers.get("content-type");
|
|
260
|
+
if (contentType == null ? void 0 : contentType.startsWith("text/html")) {
|
|
261
|
+
let htmlTemplateContent = await proxyResponse.text();
|
|
262
|
+
if (requestHost && requestProtocol) {
|
|
263
|
+
htmlTemplateContent = replaceHost(htmlTemplateContent, proxyUrl.host, requestHost, requestProtocol);
|
|
264
|
+
}
|
|
265
|
+
if (isViteDevServer(server)) {
|
|
266
|
+
const htmlTags = [];
|
|
267
|
+
htmlTags.push(`<script src='/${escapeHtml(_path2.default.relative(ctx.viteConfig.root, ctx.entry))}' type='module'></script>`);
|
|
268
|
+
const template = await server.transformIndexHtml(
|
|
269
|
+
req.url,
|
|
270
|
+
replaceBloggerPluginHeadComment(htmlTemplateContent, htmlTags.join("")),
|
|
271
|
+
req.originalUrl
|
|
272
|
+
);
|
|
273
|
+
res.end(template);
|
|
274
|
+
} else {
|
|
275
|
+
const xmlTemplateContent = _fs2.default.readFileSync(_path2.default.resolve(ctx.viteConfig.build.outDir, "template.xml"), "utf8");
|
|
276
|
+
const htmlTagsStr = getBloggerPluginHeadComment(xmlTemplateContent, true);
|
|
277
|
+
const template = replaceBloggerPluginHeadComment(htmlTemplateContent, htmlTagsStr != null ? htmlTagsStr : "");
|
|
278
|
+
res.end(template);
|
|
279
|
+
}
|
|
280
|
+
} else if (requestHost && requestProtocol && contentType && /^(text\/)|(application\/(.*\+)?(xml|json))/.test(contentType)) {
|
|
281
|
+
const content = await proxyResponse.text();
|
|
282
|
+
res.end(replaceHost(content, proxyUrl.host, requestHost, requestProtocol));
|
|
283
|
+
} else {
|
|
284
|
+
res.end(new Uint8Array(await proxyResponse.arrayBuffer()));
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
res.statusCode = 500;
|
|
288
|
+
res.statusMessage = "Internal Server Error";
|
|
289
|
+
res.setHeader("Content-Type", "text/html");
|
|
290
|
+
res.end(errorHtml(proxyUrl.href));
|
|
291
|
+
}
|
|
292
|
+
const duration = Date.now() - start;
|
|
293
|
+
_this.info(`${req.method} ${req.originalUrl} -> ${res.statusCode} ${res.statusMessage} (${duration}ms)`);
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function blogger(userOptions) {
|
|
298
|
+
const ctx = createPluginContext(userOptions);
|
|
299
|
+
return {
|
|
300
|
+
name: "vite-plugin-blogger",
|
|
301
|
+
config(config) {
|
|
302
|
+
var _a, _b, _c;
|
|
303
|
+
const root = config.root || process.cwd();
|
|
304
|
+
let entry;
|
|
305
|
+
let template;
|
|
306
|
+
if (ctx.options.entry) {
|
|
307
|
+
const providedPath = _path2.default.resolve(root, ctx.options.entry);
|
|
308
|
+
if (_fs2.default.existsSync(providedPath)) {
|
|
309
|
+
entry = providedPath;
|
|
310
|
+
} else {
|
|
311
|
+
this.error(`Provided entry file does not exist: ${providedPath}`);
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
for (const file of DEFAULT_ENTRIES) {
|
|
315
|
+
const fullPath = _path2.default.resolve(root, "src", file);
|
|
316
|
+
if (_fs2.default.existsSync(fullPath)) {
|
|
317
|
+
entry = fullPath;
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (!entry) {
|
|
322
|
+
this.error(
|
|
323
|
+
`No entry file found in "src".
|
|
324
|
+
Tried: ${DEFAULT_ENTRIES.map((c) => _path2.default.join("src", c)).join(", ")}
|
|
325
|
+
\u{1F449} Tip: You can pass a custom entry like:
|
|
326
|
+
blogger({ entry: "src/my-entry.ts" })`
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (ctx.options.template) {
|
|
331
|
+
const providedPath = _path2.default.resolve(root, ctx.options.template);
|
|
332
|
+
if (_fs2.default.existsSync(providedPath)) {
|
|
333
|
+
template = providedPath;
|
|
334
|
+
} else {
|
|
335
|
+
this.error(`Provided template file does not exist: ${providedPath}`);
|
|
336
|
+
}
|
|
337
|
+
} else {
|
|
338
|
+
for (const file of DEFAULT_TEMPLATES) {
|
|
339
|
+
const fullPath = _path2.default.resolve(root, "src", file);
|
|
340
|
+
if (_fs2.default.existsSync(fullPath)) {
|
|
341
|
+
template = fullPath;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (!template) {
|
|
346
|
+
this.error(
|
|
347
|
+
`No template file found in "src".
|
|
348
|
+
Tried: ${DEFAULT_TEMPLATES.map((c) => _path2.default.join("src", c)).join(", ")}
|
|
349
|
+
\u{1F449} Tip: You can pass a custom template like:
|
|
350
|
+
blogger({ template: "src/my-template.xml" })`
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
ctx.entry = entry;
|
|
355
|
+
ctx.template = template;
|
|
356
|
+
(_a = config.build) != null ? _a : config.build = {};
|
|
357
|
+
(_c = (_b = config.build).rollupOptions) != null ? _c : _b.rollupOptions = {};
|
|
358
|
+
config.build.rollupOptions.input = entry;
|
|
359
|
+
const xmlTemplateContent = _fs2.default.readFileSync(ctx.template, "utf8");
|
|
360
|
+
_fs2.default.writeFileSync(ctx.template, replaceBloggerPluginHeadComment(replaceBloggerPluginHeadComment(xmlTemplateContent, ""), "", true), {
|
|
361
|
+
encoding: "utf8"
|
|
362
|
+
});
|
|
363
|
+
},
|
|
364
|
+
configResolved(config) {
|
|
365
|
+
ctx.viteConfig = config;
|
|
366
|
+
},
|
|
367
|
+
generateBundle(_options, bundle) {
|
|
368
|
+
var _a;
|
|
369
|
+
for (const output of Object.values(bundle)) {
|
|
370
|
+
if (output.type !== "chunk" || !output.isEntry) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const xmlTemplateContent = _fs2.default.readFileSync(ctx.template, "utf8");
|
|
374
|
+
const htmlTags = [];
|
|
375
|
+
(_a = output.viteMetadata) == null ? void 0 : _a.importedCss.forEach((value) => {
|
|
376
|
+
htmlTags.push(`<link crossorigin='anonymous' href='${escapeHtml(ctx.viteConfig.base + value)}' rel='stylesheet'/>`);
|
|
377
|
+
});
|
|
378
|
+
htmlTags.push(`<script crossorigin='anonymous' src='${escapeHtml(ctx.viteConfig.base + output.fileName)}' type='module'></script>`);
|
|
379
|
+
const template = replaceBloggerPluginHeadComment(xmlTemplateContent, htmlTags.join(""), true);
|
|
380
|
+
this.emitFile({
|
|
381
|
+
type: "asset",
|
|
382
|
+
fileName: "template.xml",
|
|
383
|
+
source: template
|
|
384
|
+
});
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
configureServer(server) {
|
|
389
|
+
return useServerMiddleware(server, ctx, this);
|
|
390
|
+
},
|
|
391
|
+
configurePreviewServer(server) {
|
|
392
|
+
return useServerMiddleware(server, ctx, this);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
exports.default = blogger;
|
|
399
|
+
//# sourceMappingURL=vite.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/blogger-plugin/blogger-plugin/packages/blogger-plugin/dist/vite.cjs","../src/vite.ts","../src/schema.ts","../src/utils.ts"],"names":["_a"],"mappings":"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","file":"/home/runner/work/blogger-plugin/blogger-plugin/packages/blogger-plugin/dist/vite.cjs","sourcesContent":[null,"import fs from 'node:fs';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport type { MinimalPluginContextWithoutEnvironment, Plugin, PreviewServer, ResolvedConfig, ViteDevServer } from 'vite';\nimport { type BloggerPluginOptions, BloggerPluginOptionsSchema } from './schema';\nimport { errorHtml, escapeHtml, getBloggerPluginHeadComment, replaceBloggerPluginHeadComment, replaceHost, toWebHeaders } from './utils';\n\nconst DEFAULT_ENTRIES = ['index.tsx', 'index.ts', 'index.jsx', 'index.js', 'main.tsx', 'main.ts', 'main.jsx', 'main.js'];\nconst DEFAULT_TEMPLATES = ['template.xml', 'theme.xml'];\n\ninterface PluginContext {\n viteConfig: ResolvedConfig;\n entry: string;\n template: string;\n options: BloggerPluginOptions;\n}\n\nfunction createPluginContext(userOptions: BloggerPluginOptions): PluginContext {\n return {\n viteConfig: undefined as unknown as ResolvedConfig,\n entry: undefined as unknown as string,\n template: undefined as unknown as string,\n options: BloggerPluginOptionsSchema.parse(userOptions),\n };\n}\n\nfunction isViteDevServer(server: ViteDevServer | PreviewServer): server is ViteDevServer {\n return 'hot' in server && 'transformRequest' in server && 'transformIndexHtml' in server;\n}\n\nfunction useServerMiddleware(server: ViteDevServer | PreviewServer, ctx: PluginContext, _this: MinimalPluginContextWithoutEnvironment) {\n return () => {\n server.httpServer?.once('listening', () => {\n setTimeout(() => {\n _this.info(`Unhandled requests will be proxied to ${ctx.options.proxyBlog}`);\n }, 0);\n });\n\n server.middlewares.use(async (req, res, next) => {\n if (!req.url || !req.originalUrl) {\n next();\n return;\n }\n\n const start = Date.now();\n\n const proxyUrl = new URL(req.originalUrl, ctx.options.proxyBlog);\n\n const viewParam = proxyUrl.searchParams.get('view');\n proxyUrl.searchParams.set('view', `${isViteDevServer(server) ? '-DevServer' : '-PreviewServer'}${viewParam?.startsWith('-') ? viewParam : ''}`);\n\n const proxyRequest = new Request(proxyUrl, {\n method: req.method,\n headers: toWebHeaders(req.headers),\n body: ['GET', 'HEAD'].includes(req.method ?? '') ? undefined : Readable.toWeb(req),\n redirect: 'manual',\n });\n\n const proxyResponse = await fetch(proxyRequest).catch((error) => {\n if (error instanceof Error) {\n _this.warn({\n message: `${error.name}: ${error.message}`,\n cause: error.cause,\n stack: error.stack,\n });\n } else {\n _this.warn('Fetch failed');\n }\n return null;\n });\n\n if (proxyResponse) {\n const requestProtocol = `${(req.headers['x-forwarded-proto'] as string) || (req.socket && 'encrypted' in req.socket && req.socket.encrypted ? 'https' : 'http')}:`;\n const requestHost = (req.headers['x-forwarded-host'] as string) || req.headers.host;\n\n res.statusCode = proxyResponse.status;\n res.statusMessage = proxyResponse.statusText;\n\n proxyResponse.headers.forEach((value, key) => {\n if (key === 'location') {\n const redirectUrl = new URL(value, requestHost ? `${requestProtocol}//${requestHost}${req.originalUrl}` : proxyUrl.href);\n if ((requestHost && redirectUrl.host === requestHost) || redirectUrl.host === proxyUrl.host) {\n if (requestHost && requestProtocol) {\n redirectUrl.host = requestHost;\n redirectUrl.protocol = requestProtocol;\n }\n const viewParam = redirectUrl.searchParams.get('view')?.replaceAll('-DevServer', '').replaceAll('-PreviewServer', '');\n if (viewParam) {\n redirectUrl.searchParams.set('view', viewParam);\n } else {\n redirectUrl.searchParams.delete('view');\n }\n res.setHeader(key, redirectUrl.pathname + redirectUrl.search + redirectUrl.hash);\n } else {\n res.setHeader(key, redirectUrl.href);\n }\n } else if (['content-type', 'x-robots-tag', 'date', 'location'].includes(key)) {\n res.setHeader(key, value);\n }\n });\n\n const contentType = proxyResponse.headers.get('content-type');\n\n if (contentType?.startsWith('text/html')) {\n let htmlTemplateContent = await proxyResponse.text();\n\n if (requestHost && requestProtocol) {\n htmlTemplateContent = replaceHost(htmlTemplateContent, proxyUrl.host, requestHost, requestProtocol);\n }\n\n if (isViteDevServer(server)) {\n const htmlTags: string[] = [];\n\n htmlTags.push(`<script src='/${escapeHtml(path.relative(ctx.viteConfig.root, ctx.entry))}' type='module'></script>`);\n\n const template = await server.transformIndexHtml(\n req.url,\n replaceBloggerPluginHeadComment(htmlTemplateContent, htmlTags.join('')),\n req.originalUrl,\n );\n\n res.end(template);\n } else {\n const xmlTemplateContent = fs.readFileSync(path.resolve(ctx.viteConfig.build.outDir, 'template.xml'), 'utf8');\n\n const htmlTagsStr = getBloggerPluginHeadComment(xmlTemplateContent, true);\n\n const template = replaceBloggerPluginHeadComment(htmlTemplateContent, htmlTagsStr ?? '');\n\n res.end(template);\n }\n } else if (requestHost && requestProtocol && contentType && /^(text\\/)|(application\\/(.*\\+)?(xml|json))/.test(contentType)) {\n const content = await proxyResponse.text();\n\n res.end(replaceHost(content, proxyUrl.host, requestHost, requestProtocol));\n } else {\n res.end(new Uint8Array(await proxyResponse.arrayBuffer()));\n }\n } else {\n res.statusCode = 500;\n res.statusMessage = 'Internal Server Error';\n\n res.setHeader('Content-Type', 'text/html');\n\n res.end(errorHtml(proxyUrl.href));\n }\n\n const duration = Date.now() - start;\n\n _this.info(`${req.method} ${req.originalUrl} -> ${res.statusCode} ${res.statusMessage} (${duration}ms)`);\n });\n };\n}\n\nexport default function blogger(userOptions: BloggerPluginOptions): Plugin {\n const ctx = createPluginContext(userOptions);\n\n return {\n name: 'vite-plugin-blogger',\n config(config) {\n const root = config.root || process.cwd();\n\n let entry: string | undefined;\n let template: string | undefined;\n\n if (ctx.options.entry) {\n const providedPath = path.resolve(root, ctx.options.entry);\n if (fs.existsSync(providedPath)) {\n entry = providedPath;\n } else {\n this.error(`Provided entry file does not exist: ${providedPath}`);\n }\n } else {\n for (const file of DEFAULT_ENTRIES) {\n const fullPath = path.resolve(root, 'src', file);\n if (fs.existsSync(fullPath)) {\n entry = fullPath;\n break;\n }\n }\n\n if (!entry) {\n this.error(\n 'No entry file found in \"src\".\\n' +\n `Tried: ${DEFAULT_ENTRIES.map((c) => path.join('src', c)).join(', ')}\\n` +\n '👉 Tip: You can pass a custom entry like:\\n' +\n ' blogger({ entry: \"src/my-entry.ts\" })',\n );\n }\n }\n\n if (ctx.options.template) {\n const providedPath = path.resolve(root, ctx.options.template);\n if (fs.existsSync(providedPath)) {\n template = providedPath;\n } else {\n this.error(`Provided template file does not exist: ${providedPath}`);\n }\n } else {\n for (const file of DEFAULT_TEMPLATES) {\n const fullPath = path.resolve(root, 'src', file);\n if (fs.existsSync(fullPath)) {\n template = fullPath;\n break;\n }\n }\n\n if (!template) {\n this.error(\n 'No template file found in \"src\".\\n' +\n `Tried: ${DEFAULT_TEMPLATES.map((c) => path.join('src', c)).join(', ')}\\n` +\n '👉 Tip: You can pass a custom template like:\\n' +\n ' blogger({ template: \"src/my-template.xml\" })',\n );\n }\n }\n\n // populate plugin context\n ctx.entry = entry as string;\n ctx.template = template as string;\n\n // override vite config\n config.build ??= {};\n config.build.rollupOptions ??= {};\n config.build.rollupOptions.input = entry;\n\n // remove contents between comments from template\n const xmlTemplateContent = fs.readFileSync(ctx.template, 'utf8');\n fs.writeFileSync(ctx.template, replaceBloggerPluginHeadComment(replaceBloggerPluginHeadComment(xmlTemplateContent, ''), '', true), {\n encoding: 'utf8',\n });\n },\n configResolved(config) {\n ctx.viteConfig = config;\n },\n generateBundle(_options, bundle) {\n for (const output of Object.values(bundle)) {\n if (output.type !== 'chunk' || !output.isEntry) {\n continue;\n }\n\n const xmlTemplateContent = fs.readFileSync(ctx.template, 'utf8');\n\n const htmlTags: string[] = [];\n output.viteMetadata?.importedCss.forEach((value) => {\n htmlTags.push(`<link crossorigin='anonymous' href='${escapeHtml(ctx.viteConfig.base + value)}' rel='stylesheet'/>`);\n });\n htmlTags.push(`<script crossorigin='anonymous' src='${escapeHtml(ctx.viteConfig.base + output.fileName)}' type='module'></script>`);\n\n const template = replaceBloggerPluginHeadComment(xmlTemplateContent, htmlTags.join(''), true);\n\n this.emitFile({\n type: 'asset',\n fileName: 'template.xml',\n source: template,\n });\n\n break;\n }\n },\n configureServer(server) {\n return useServerMiddleware(server, ctx, this);\n },\n configurePreviewServer(server) {\n return useServerMiddleware(server, ctx, this);\n },\n };\n}\n\nexport type { BloggerPluginOptions } from './schema';\n","import { z } from 'zod';\n\nexport const BloggerPluginOptionsSchema = z\n .object({\n entry: z.string().optional(),\n template: z.string().optional(),\n proxyBlog: z.url(),\n })\n .strict();\n\nexport type BloggerPluginOptions = z.infer<typeof BloggerPluginOptionsSchema>;\n","import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'node:http';\n\nexport function escapeHtml(str: string) {\n if (str === '') return '';\n return str.replace(/[&<>\"'`]/g, (ch) => {\n switch (ch) {\n case '&':\n return '&';\n case '<':\n return '<';\n case '>':\n return '>';\n case '\"':\n return '"';\n case \"'\":\n return ''';\n case '`':\n return '`';\n default:\n return ch;\n }\n });\n}\n\nexport function escapeRegex(str: string) {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function toWebHeaders(httpHeaders: IncomingHttpHeaders | OutgoingHttpHeaders): Headers {\n const headers = new Headers();\n for (const [name, value] of Object.entries(httpHeaders)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n headers.append(name, item);\n }\n } else {\n headers.set(name, String(value ?? ''));\n }\n }\n return headers;\n}\n\nexport function replaceBloggerPluginHeadComment(input: string, replacement: string, bcomment = false) {\n if (bcomment) {\n return input.replace(\n /<b:comment><!--blogger-plugin:head:begin--><\\/b:comment>[\\s\\S]*?<b:comment><!--blogger-plugin:head:end--><\\/b:comment>/,\n `<b:comment><!--blogger-plugin:head:begin--></b:comment>${replacement}<b:comment><!--blogger-plugin:head:end--></b:comment>`,\n );\n }\n return input.replace(\n /<!--blogger-plugin:head:begin-->[\\s\\S]*?<!--blogger-plugin:head:end-->/,\n `<!--blogger-plugin:head:begin-->${replacement}<!--blogger-plugin:head:end-->`,\n );\n}\n\nexport function getBloggerPluginHeadComment(input: string, bcomment = false) {\n if (bcomment) {\n return (\n input.match(/<b:comment><!--blogger-plugin:head:begin--><\\/b:comment>([\\s\\S]*?)<b:comment><!--blogger-plugin:head:end--><\\/b:comment>/)?.[1] ??\n null\n );\n }\n return input.match(/<!--blogger-plugin:head:begin-->([\\s\\S]*?)<!--blogger-plugin:head:end-->/)?.[1] ?? null;\n}\n\nexport function replaceHost(input: string, oldHost: string, newHost: string, newProtocol?: string) {\n return input.replace(\n new RegExp(`(https?:)?(\\\\/\\\\/|\\\\\\\\/\\\\\\\\/)${escapeRegex(oldHost)}`, 'g'),\n (_, protocol, slash) => `${protocol ? (newProtocol ?? protocol) : ''}${slash ?? ''}${newHost}`,\n );\n}\n\nexport function errorHtml(reqUrl: string) {\n return `<!DOCTYPE html>\n<html>\n\n<head>\n <meta charset='UTF-8'/>\n <meta content='width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=5, user-scalable=yes' name='viewport'/>\n <title>500 Internal Server Error</title>\n <link rel='icon' href='data:,' />\n <style>\n *, ::before, ::after {\n box-sizing: border-box;\n }\n body {\n min-height: 100svh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n margin: 0;\n padding: 20px;\n background-color: #f5f5f5;\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", Segoe UI Symbol, \"Noto Color Emoji\";\n }\n .card {\n padding: 24px;\n background-color: #ffffff;\n border: 1px solid #e5e5e5;\n max-width: 448px;\n border-radius: 14px;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n .card-content {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n .card-title {\n font-weight: 600;\n }\n .card-description {\n font-size: 14px;\n opacity: 0.85;\n }\n .card-footer {\n display: flex;\n align-items: center;\n }\n .button {\n display: inline-flex;\n white-space: nowrap;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 8px 16px;\n font-weight: 500;\n background-color: #171717;\n outline: none;\n border: none;\n color: #ffffff;\n border-radius: 8px;\n min-height: 36px;\n }\n .button:hover {\n opacity: 0.9;\n }\n .button svg {\n wiheadersdth: 16px;\n height: 16px;\n flex-shrink: 0;\n }\n .card-footer .button {\n flex-grow: 1;\n }\n </style>\n</head>\n\n<body>\n <div class='card'>\n <div class='card-content'>\n <div class='card-title'>500 Internal Server Error</div>\n <div class='card-description'>Failed to fetch: ${escapeHtml(reqUrl)}</div>\n </div>\n <div class='card-footer'>\n <button class='button' type='button'>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-refresh-ccw\" aria-hidden=\"true\"><path d=\"M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"></path><path d=\"M3 3v5h5\"></path><path d=\"M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16\"></path><path d=\"M16 16h5v5\"></path></svg>\n Reload\n </button>\n </div>\n </div>\n <script>\n const button = document.getElementsByTagName('button')[0];\n button.addEventListener('click', () => {\n window.location.reload();\n });\n </script>\n</body>\n\n</html>`;\n}\n"]}
|
package/dist/vite.d.cts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
declare const BloggerPluginOptionsSchema: z.ZodObject<{
|
|
5
|
+
entry: z.ZodOptional<z.ZodString>;
|
|
6
|
+
template: z.ZodOptional<z.ZodString>;
|
|
7
|
+
proxyBlog: z.ZodURL;
|
|
8
|
+
}, z.core.$strict>;
|
|
9
|
+
type BloggerPluginOptions = z.infer<typeof BloggerPluginOptionsSchema>;
|
|
10
|
+
|
|
11
|
+
declare function blogger(userOptions: BloggerPluginOptions): Plugin;
|
|
12
|
+
|
|
13
|
+
export { type BloggerPluginOptions, blogger as default };
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
declare const BloggerPluginOptionsSchema: z.ZodObject<{
|
|
5
|
+
entry: z.ZodOptional<z.ZodString>;
|
|
6
|
+
template: z.ZodOptional<z.ZodString>;
|
|
7
|
+
proxyBlog: z.ZodURL;
|
|
8
|
+
}, z.core.$strict>;
|
|
9
|
+
type BloggerPluginOptions = z.infer<typeof BloggerPluginOptionsSchema>;
|
|
10
|
+
|
|
11
|
+
declare function blogger(userOptions: BloggerPluginOptions): Plugin;
|
|
12
|
+
|
|
13
|
+
export { type BloggerPluginOptions, blogger as default };
|
package/dist/vite.js
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
// src/vite.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { Readable } from "stream";
|
|
5
|
+
|
|
6
|
+
// src/schema.ts
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
var BloggerPluginOptionsSchema = z.object({
|
|
9
|
+
entry: z.string().optional(),
|
|
10
|
+
template: z.string().optional(),
|
|
11
|
+
proxyBlog: z.url()
|
|
12
|
+
}).strict();
|
|
13
|
+
|
|
14
|
+
// src/utils.ts
|
|
15
|
+
function escapeHtml(str) {
|
|
16
|
+
if (str === "") return "";
|
|
17
|
+
return str.replace(/[&<>"'`]/g, (ch) => {
|
|
18
|
+
switch (ch) {
|
|
19
|
+
case "&":
|
|
20
|
+
return "&";
|
|
21
|
+
case "<":
|
|
22
|
+
return "<";
|
|
23
|
+
case ">":
|
|
24
|
+
return ">";
|
|
25
|
+
case '"':
|
|
26
|
+
return """;
|
|
27
|
+
case "'":
|
|
28
|
+
return "'";
|
|
29
|
+
case "`":
|
|
30
|
+
return "`";
|
|
31
|
+
default:
|
|
32
|
+
return ch;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function escapeRegex(str) {
|
|
37
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
38
|
+
}
|
|
39
|
+
function toWebHeaders(httpHeaders) {
|
|
40
|
+
const headers = new Headers();
|
|
41
|
+
for (const [name, value] of Object.entries(httpHeaders)) {
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
for (const item of value) {
|
|
44
|
+
headers.append(name, item);
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
headers.set(name, String(value != null ? value : ""));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return headers;
|
|
51
|
+
}
|
|
52
|
+
function replaceBloggerPluginHeadComment(input, replacement, bcomment = false) {
|
|
53
|
+
if (bcomment) {
|
|
54
|
+
return input.replace(
|
|
55
|
+
/<b:comment><!--blogger-plugin:head:begin--><\/b:comment>[\s\S]*?<b:comment><!--blogger-plugin:head:end--><\/b:comment>/,
|
|
56
|
+
`<b:comment><!--blogger-plugin:head:begin--></b:comment>${replacement}<b:comment><!--blogger-plugin:head:end--></b:comment>`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return input.replace(
|
|
60
|
+
/<!--blogger-plugin:head:begin-->[\s\S]*?<!--blogger-plugin:head:end-->/,
|
|
61
|
+
`<!--blogger-plugin:head:begin-->${replacement}<!--blogger-plugin:head:end-->`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
function getBloggerPluginHeadComment(input, bcomment = false) {
|
|
65
|
+
var _a, _b, _c, _d;
|
|
66
|
+
if (bcomment) {
|
|
67
|
+
return (_b = (_a = input.match(/<b:comment><!--blogger-plugin:head:begin--><\/b:comment>([\s\S]*?)<b:comment><!--blogger-plugin:head:end--><\/b:comment>/)) == null ? void 0 : _a[1]) != null ? _b : null;
|
|
68
|
+
}
|
|
69
|
+
return (_d = (_c = input.match(/<!--blogger-plugin:head:begin-->([\s\S]*?)<!--blogger-plugin:head:end-->/)) == null ? void 0 : _c[1]) != null ? _d : null;
|
|
70
|
+
}
|
|
71
|
+
function replaceHost(input, oldHost, newHost, newProtocol) {
|
|
72
|
+
return input.replace(
|
|
73
|
+
new RegExp(`(https?:)?(\\/\\/|\\\\/\\\\/)${escapeRegex(oldHost)}`, "g"),
|
|
74
|
+
(_, protocol, slash) => `${protocol ? newProtocol != null ? newProtocol : protocol : ""}${slash != null ? slash : ""}${newHost}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
function errorHtml(reqUrl) {
|
|
78
|
+
return `<!DOCTYPE html>
|
|
79
|
+
<html>
|
|
80
|
+
|
|
81
|
+
<head>
|
|
82
|
+
<meta charset='UTF-8'/>
|
|
83
|
+
<meta content='width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=5, user-scalable=yes' name='viewport'/>
|
|
84
|
+
<title>500 Internal Server Error</title>
|
|
85
|
+
<link rel='icon' href='data:,' />
|
|
86
|
+
<style>
|
|
87
|
+
*, ::before, ::after {
|
|
88
|
+
box-sizing: border-box;
|
|
89
|
+
}
|
|
90
|
+
body {
|
|
91
|
+
min-height: 100svh;
|
|
92
|
+
display: flex;
|
|
93
|
+
flex-direction: column;
|
|
94
|
+
align-items: center;
|
|
95
|
+
justify-content: center;
|
|
96
|
+
margin: 0;
|
|
97
|
+
padding: 20px;
|
|
98
|
+
background-color: #f5f5f5;
|
|
99
|
+
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", Segoe UI Symbol, "Noto Color Emoji";
|
|
100
|
+
}
|
|
101
|
+
.card {
|
|
102
|
+
padding: 24px;
|
|
103
|
+
background-color: #ffffff;
|
|
104
|
+
border: 1px solid #e5e5e5;
|
|
105
|
+
max-width: 448px;
|
|
106
|
+
border-radius: 14px;
|
|
107
|
+
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
|
|
108
|
+
display: flex;
|
|
109
|
+
flex-direction: column;
|
|
110
|
+
gap: 24px;
|
|
111
|
+
}
|
|
112
|
+
.card-content {
|
|
113
|
+
display: flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
gap: 6px;
|
|
116
|
+
}
|
|
117
|
+
.card-title {
|
|
118
|
+
font-weight: 600;
|
|
119
|
+
}
|
|
120
|
+
.card-description {
|
|
121
|
+
font-size: 14px;
|
|
122
|
+
opacity: 0.85;
|
|
123
|
+
}
|
|
124
|
+
.card-footer {
|
|
125
|
+
display: flex;
|
|
126
|
+
align-items: center;
|
|
127
|
+
}
|
|
128
|
+
.button {
|
|
129
|
+
display: inline-flex;
|
|
130
|
+
white-space: nowrap;
|
|
131
|
+
align-items: center;
|
|
132
|
+
justify-content: center;
|
|
133
|
+
gap: 8px;
|
|
134
|
+
padding: 8px 16px;
|
|
135
|
+
font-weight: 500;
|
|
136
|
+
background-color: #171717;
|
|
137
|
+
outline: none;
|
|
138
|
+
border: none;
|
|
139
|
+
color: #ffffff;
|
|
140
|
+
border-radius: 8px;
|
|
141
|
+
min-height: 36px;
|
|
142
|
+
}
|
|
143
|
+
.button:hover {
|
|
144
|
+
opacity: 0.9;
|
|
145
|
+
}
|
|
146
|
+
.button svg {
|
|
147
|
+
wiheadersdth: 16px;
|
|
148
|
+
height: 16px;
|
|
149
|
+
flex-shrink: 0;
|
|
150
|
+
}
|
|
151
|
+
.card-footer .button {
|
|
152
|
+
flex-grow: 1;
|
|
153
|
+
}
|
|
154
|
+
</style>
|
|
155
|
+
</head>
|
|
156
|
+
|
|
157
|
+
<body>
|
|
158
|
+
<div class='card'>
|
|
159
|
+
<div class='card-content'>
|
|
160
|
+
<div class='card-title'>500 Internal Server Error</div>
|
|
161
|
+
<div class='card-description'>Failed to fetch: ${escapeHtml(reqUrl)}</div>
|
|
162
|
+
</div>
|
|
163
|
+
<div class='card-footer'>
|
|
164
|
+
<button class='button' type='button'>
|
|
165
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-refresh-ccw" aria-hidden="true"><path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path><path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"></path><path d="M16 16h5v5"></path></svg>
|
|
166
|
+
Reload
|
|
167
|
+
</button>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
<script>
|
|
171
|
+
const button = document.getElementsByTagName('button')[0];
|
|
172
|
+
button.addEventListener('click', () => {
|
|
173
|
+
window.location.reload();
|
|
174
|
+
});
|
|
175
|
+
</script>
|
|
176
|
+
</body>
|
|
177
|
+
|
|
178
|
+
</html>`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// src/vite.ts
|
|
182
|
+
var DEFAULT_ENTRIES = ["index.tsx", "index.ts", "index.jsx", "index.js", "main.tsx", "main.ts", "main.jsx", "main.js"];
|
|
183
|
+
var DEFAULT_TEMPLATES = ["template.xml", "theme.xml"];
|
|
184
|
+
function createPluginContext(userOptions) {
|
|
185
|
+
return {
|
|
186
|
+
viteConfig: void 0,
|
|
187
|
+
entry: void 0,
|
|
188
|
+
template: void 0,
|
|
189
|
+
options: BloggerPluginOptionsSchema.parse(userOptions)
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function isViteDevServer(server) {
|
|
193
|
+
return "hot" in server && "transformRequest" in server && "transformIndexHtml" in server;
|
|
194
|
+
}
|
|
195
|
+
function useServerMiddleware(server, ctx, _this) {
|
|
196
|
+
return () => {
|
|
197
|
+
var _a;
|
|
198
|
+
(_a = server.httpServer) == null ? void 0 : _a.once("listening", () => {
|
|
199
|
+
setTimeout(() => {
|
|
200
|
+
_this.info(`Unhandled requests will be proxied to ${ctx.options.proxyBlog}`);
|
|
201
|
+
}, 0);
|
|
202
|
+
});
|
|
203
|
+
server.middlewares.use(async (req, res, next) => {
|
|
204
|
+
var _a2;
|
|
205
|
+
if (!req.url || !req.originalUrl) {
|
|
206
|
+
next();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const start = Date.now();
|
|
210
|
+
const proxyUrl = new URL(req.originalUrl, ctx.options.proxyBlog);
|
|
211
|
+
const viewParam = proxyUrl.searchParams.get("view");
|
|
212
|
+
proxyUrl.searchParams.set("view", `${isViteDevServer(server) ? "-DevServer" : "-PreviewServer"}${(viewParam == null ? void 0 : viewParam.startsWith("-")) ? viewParam : ""}`);
|
|
213
|
+
const proxyRequest = new Request(proxyUrl, {
|
|
214
|
+
method: req.method,
|
|
215
|
+
headers: toWebHeaders(req.headers),
|
|
216
|
+
body: ["GET", "HEAD"].includes((_a2 = req.method) != null ? _a2 : "") ? void 0 : Readable.toWeb(req),
|
|
217
|
+
redirect: "manual"
|
|
218
|
+
});
|
|
219
|
+
const proxyResponse = await fetch(proxyRequest).catch((error) => {
|
|
220
|
+
if (error instanceof Error) {
|
|
221
|
+
_this.warn({
|
|
222
|
+
message: `${error.name}: ${error.message}`,
|
|
223
|
+
cause: error.cause,
|
|
224
|
+
stack: error.stack
|
|
225
|
+
});
|
|
226
|
+
} else {
|
|
227
|
+
_this.warn("Fetch failed");
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
});
|
|
231
|
+
if (proxyResponse) {
|
|
232
|
+
const requestProtocol = `${req.headers["x-forwarded-proto"] || (req.socket && "encrypted" in req.socket && req.socket.encrypted ? "https" : "http")}:`;
|
|
233
|
+
const requestHost = req.headers["x-forwarded-host"] || req.headers.host;
|
|
234
|
+
res.statusCode = proxyResponse.status;
|
|
235
|
+
res.statusMessage = proxyResponse.statusText;
|
|
236
|
+
proxyResponse.headers.forEach((value, key) => {
|
|
237
|
+
var _a3;
|
|
238
|
+
if (key === "location") {
|
|
239
|
+
const redirectUrl = new URL(value, requestHost ? `${requestProtocol}//${requestHost}${req.originalUrl}` : proxyUrl.href);
|
|
240
|
+
if (requestHost && redirectUrl.host === requestHost || redirectUrl.host === proxyUrl.host) {
|
|
241
|
+
if (requestHost && requestProtocol) {
|
|
242
|
+
redirectUrl.host = requestHost;
|
|
243
|
+
redirectUrl.protocol = requestProtocol;
|
|
244
|
+
}
|
|
245
|
+
const viewParam2 = (_a3 = redirectUrl.searchParams.get("view")) == null ? void 0 : _a3.replaceAll("-DevServer", "").replaceAll("-PreviewServer", "");
|
|
246
|
+
if (viewParam2) {
|
|
247
|
+
redirectUrl.searchParams.set("view", viewParam2);
|
|
248
|
+
} else {
|
|
249
|
+
redirectUrl.searchParams.delete("view");
|
|
250
|
+
}
|
|
251
|
+
res.setHeader(key, redirectUrl.pathname + redirectUrl.search + redirectUrl.hash);
|
|
252
|
+
} else {
|
|
253
|
+
res.setHeader(key, redirectUrl.href);
|
|
254
|
+
}
|
|
255
|
+
} else if (["content-type", "x-robots-tag", "date", "location"].includes(key)) {
|
|
256
|
+
res.setHeader(key, value);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
const contentType = proxyResponse.headers.get("content-type");
|
|
260
|
+
if (contentType == null ? void 0 : contentType.startsWith("text/html")) {
|
|
261
|
+
let htmlTemplateContent = await proxyResponse.text();
|
|
262
|
+
if (requestHost && requestProtocol) {
|
|
263
|
+
htmlTemplateContent = replaceHost(htmlTemplateContent, proxyUrl.host, requestHost, requestProtocol);
|
|
264
|
+
}
|
|
265
|
+
if (isViteDevServer(server)) {
|
|
266
|
+
const htmlTags = [];
|
|
267
|
+
htmlTags.push(`<script src='/${escapeHtml(path.relative(ctx.viteConfig.root, ctx.entry))}' type='module'></script>`);
|
|
268
|
+
const template = await server.transformIndexHtml(
|
|
269
|
+
req.url,
|
|
270
|
+
replaceBloggerPluginHeadComment(htmlTemplateContent, htmlTags.join("")),
|
|
271
|
+
req.originalUrl
|
|
272
|
+
);
|
|
273
|
+
res.end(template);
|
|
274
|
+
} else {
|
|
275
|
+
const xmlTemplateContent = fs.readFileSync(path.resolve(ctx.viteConfig.build.outDir, "template.xml"), "utf8");
|
|
276
|
+
const htmlTagsStr = getBloggerPluginHeadComment(xmlTemplateContent, true);
|
|
277
|
+
const template = replaceBloggerPluginHeadComment(htmlTemplateContent, htmlTagsStr != null ? htmlTagsStr : "");
|
|
278
|
+
res.end(template);
|
|
279
|
+
}
|
|
280
|
+
} else if (requestHost && requestProtocol && contentType && /^(text\/)|(application\/(.*\+)?(xml|json))/.test(contentType)) {
|
|
281
|
+
const content = await proxyResponse.text();
|
|
282
|
+
res.end(replaceHost(content, proxyUrl.host, requestHost, requestProtocol));
|
|
283
|
+
} else {
|
|
284
|
+
res.end(new Uint8Array(await proxyResponse.arrayBuffer()));
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
res.statusCode = 500;
|
|
288
|
+
res.statusMessage = "Internal Server Error";
|
|
289
|
+
res.setHeader("Content-Type", "text/html");
|
|
290
|
+
res.end(errorHtml(proxyUrl.href));
|
|
291
|
+
}
|
|
292
|
+
const duration = Date.now() - start;
|
|
293
|
+
_this.info(`${req.method} ${req.originalUrl} -> ${res.statusCode} ${res.statusMessage} (${duration}ms)`);
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function blogger(userOptions) {
|
|
298
|
+
const ctx = createPluginContext(userOptions);
|
|
299
|
+
return {
|
|
300
|
+
name: "vite-plugin-blogger",
|
|
301
|
+
config(config) {
|
|
302
|
+
var _a, _b, _c;
|
|
303
|
+
const root = config.root || process.cwd();
|
|
304
|
+
let entry;
|
|
305
|
+
let template;
|
|
306
|
+
if (ctx.options.entry) {
|
|
307
|
+
const providedPath = path.resolve(root, ctx.options.entry);
|
|
308
|
+
if (fs.existsSync(providedPath)) {
|
|
309
|
+
entry = providedPath;
|
|
310
|
+
} else {
|
|
311
|
+
this.error(`Provided entry file does not exist: ${providedPath}`);
|
|
312
|
+
}
|
|
313
|
+
} else {
|
|
314
|
+
for (const file of DEFAULT_ENTRIES) {
|
|
315
|
+
const fullPath = path.resolve(root, "src", file);
|
|
316
|
+
if (fs.existsSync(fullPath)) {
|
|
317
|
+
entry = fullPath;
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (!entry) {
|
|
322
|
+
this.error(
|
|
323
|
+
`No entry file found in "src".
|
|
324
|
+
Tried: ${DEFAULT_ENTRIES.map((c) => path.join("src", c)).join(", ")}
|
|
325
|
+
\u{1F449} Tip: You can pass a custom entry like:
|
|
326
|
+
blogger({ entry: "src/my-entry.ts" })`
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (ctx.options.template) {
|
|
331
|
+
const providedPath = path.resolve(root, ctx.options.template);
|
|
332
|
+
if (fs.existsSync(providedPath)) {
|
|
333
|
+
template = providedPath;
|
|
334
|
+
} else {
|
|
335
|
+
this.error(`Provided template file does not exist: ${providedPath}`);
|
|
336
|
+
}
|
|
337
|
+
} else {
|
|
338
|
+
for (const file of DEFAULT_TEMPLATES) {
|
|
339
|
+
const fullPath = path.resolve(root, "src", file);
|
|
340
|
+
if (fs.existsSync(fullPath)) {
|
|
341
|
+
template = fullPath;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (!template) {
|
|
346
|
+
this.error(
|
|
347
|
+
`No template file found in "src".
|
|
348
|
+
Tried: ${DEFAULT_TEMPLATES.map((c) => path.join("src", c)).join(", ")}
|
|
349
|
+
\u{1F449} Tip: You can pass a custom template like:
|
|
350
|
+
blogger({ template: "src/my-template.xml" })`
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
ctx.entry = entry;
|
|
355
|
+
ctx.template = template;
|
|
356
|
+
(_a = config.build) != null ? _a : config.build = {};
|
|
357
|
+
(_c = (_b = config.build).rollupOptions) != null ? _c : _b.rollupOptions = {};
|
|
358
|
+
config.build.rollupOptions.input = entry;
|
|
359
|
+
const xmlTemplateContent = fs.readFileSync(ctx.template, "utf8");
|
|
360
|
+
fs.writeFileSync(ctx.template, replaceBloggerPluginHeadComment(replaceBloggerPluginHeadComment(xmlTemplateContent, ""), "", true), {
|
|
361
|
+
encoding: "utf8"
|
|
362
|
+
});
|
|
363
|
+
},
|
|
364
|
+
configResolved(config) {
|
|
365
|
+
ctx.viteConfig = config;
|
|
366
|
+
},
|
|
367
|
+
generateBundle(_options, bundle) {
|
|
368
|
+
var _a;
|
|
369
|
+
for (const output of Object.values(bundle)) {
|
|
370
|
+
if (output.type !== "chunk" || !output.isEntry) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const xmlTemplateContent = fs.readFileSync(ctx.template, "utf8");
|
|
374
|
+
const htmlTags = [];
|
|
375
|
+
(_a = output.viteMetadata) == null ? void 0 : _a.importedCss.forEach((value) => {
|
|
376
|
+
htmlTags.push(`<link crossorigin='anonymous' href='${escapeHtml(ctx.viteConfig.base + value)}' rel='stylesheet'/>`);
|
|
377
|
+
});
|
|
378
|
+
htmlTags.push(`<script crossorigin='anonymous' src='${escapeHtml(ctx.viteConfig.base + output.fileName)}' type='module'></script>`);
|
|
379
|
+
const template = replaceBloggerPluginHeadComment(xmlTemplateContent, htmlTags.join(""), true);
|
|
380
|
+
this.emitFile({
|
|
381
|
+
type: "asset",
|
|
382
|
+
fileName: "template.xml",
|
|
383
|
+
source: template
|
|
384
|
+
});
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
configureServer(server) {
|
|
389
|
+
return useServerMiddleware(server, ctx, this);
|
|
390
|
+
},
|
|
391
|
+
configurePreviewServer(server) {
|
|
392
|
+
return useServerMiddleware(server, ctx, this);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
export {
|
|
397
|
+
blogger as default
|
|
398
|
+
};
|
|
399
|
+
//# sourceMappingURL=vite.js.map
|
package/dist/vite.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vite.ts","../src/schema.ts","../src/utils.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { Readable } from 'node:stream';\nimport type { MinimalPluginContextWithoutEnvironment, Plugin, PreviewServer, ResolvedConfig, ViteDevServer } from 'vite';\nimport { type BloggerPluginOptions, BloggerPluginOptionsSchema } from './schema';\nimport { errorHtml, escapeHtml, getBloggerPluginHeadComment, replaceBloggerPluginHeadComment, replaceHost, toWebHeaders } from './utils';\n\nconst DEFAULT_ENTRIES = ['index.tsx', 'index.ts', 'index.jsx', 'index.js', 'main.tsx', 'main.ts', 'main.jsx', 'main.js'];\nconst DEFAULT_TEMPLATES = ['template.xml', 'theme.xml'];\n\ninterface PluginContext {\n viteConfig: ResolvedConfig;\n entry: string;\n template: string;\n options: BloggerPluginOptions;\n}\n\nfunction createPluginContext(userOptions: BloggerPluginOptions): PluginContext {\n return {\n viteConfig: undefined as unknown as ResolvedConfig,\n entry: undefined as unknown as string,\n template: undefined as unknown as string,\n options: BloggerPluginOptionsSchema.parse(userOptions),\n };\n}\n\nfunction isViteDevServer(server: ViteDevServer | PreviewServer): server is ViteDevServer {\n return 'hot' in server && 'transformRequest' in server && 'transformIndexHtml' in server;\n}\n\nfunction useServerMiddleware(server: ViteDevServer | PreviewServer, ctx: PluginContext, _this: MinimalPluginContextWithoutEnvironment) {\n return () => {\n server.httpServer?.once('listening', () => {\n setTimeout(() => {\n _this.info(`Unhandled requests will be proxied to ${ctx.options.proxyBlog}`);\n }, 0);\n });\n\n server.middlewares.use(async (req, res, next) => {\n if (!req.url || !req.originalUrl) {\n next();\n return;\n }\n\n const start = Date.now();\n\n const proxyUrl = new URL(req.originalUrl, ctx.options.proxyBlog);\n\n const viewParam = proxyUrl.searchParams.get('view');\n proxyUrl.searchParams.set('view', `${isViteDevServer(server) ? '-DevServer' : '-PreviewServer'}${viewParam?.startsWith('-') ? viewParam : ''}`);\n\n const proxyRequest = new Request(proxyUrl, {\n method: req.method,\n headers: toWebHeaders(req.headers),\n body: ['GET', 'HEAD'].includes(req.method ?? '') ? undefined : Readable.toWeb(req),\n redirect: 'manual',\n });\n\n const proxyResponse = await fetch(proxyRequest).catch((error) => {\n if (error instanceof Error) {\n _this.warn({\n message: `${error.name}: ${error.message}`,\n cause: error.cause,\n stack: error.stack,\n });\n } else {\n _this.warn('Fetch failed');\n }\n return null;\n });\n\n if (proxyResponse) {\n const requestProtocol = `${(req.headers['x-forwarded-proto'] as string) || (req.socket && 'encrypted' in req.socket && req.socket.encrypted ? 'https' : 'http')}:`;\n const requestHost = (req.headers['x-forwarded-host'] as string) || req.headers.host;\n\n res.statusCode = proxyResponse.status;\n res.statusMessage = proxyResponse.statusText;\n\n proxyResponse.headers.forEach((value, key) => {\n if (key === 'location') {\n const redirectUrl = new URL(value, requestHost ? `${requestProtocol}//${requestHost}${req.originalUrl}` : proxyUrl.href);\n if ((requestHost && redirectUrl.host === requestHost) || redirectUrl.host === proxyUrl.host) {\n if (requestHost && requestProtocol) {\n redirectUrl.host = requestHost;\n redirectUrl.protocol = requestProtocol;\n }\n const viewParam = redirectUrl.searchParams.get('view')?.replaceAll('-DevServer', '').replaceAll('-PreviewServer', '');\n if (viewParam) {\n redirectUrl.searchParams.set('view', viewParam);\n } else {\n redirectUrl.searchParams.delete('view');\n }\n res.setHeader(key, redirectUrl.pathname + redirectUrl.search + redirectUrl.hash);\n } else {\n res.setHeader(key, redirectUrl.href);\n }\n } else if (['content-type', 'x-robots-tag', 'date', 'location'].includes(key)) {\n res.setHeader(key, value);\n }\n });\n\n const contentType = proxyResponse.headers.get('content-type');\n\n if (contentType?.startsWith('text/html')) {\n let htmlTemplateContent = await proxyResponse.text();\n\n if (requestHost && requestProtocol) {\n htmlTemplateContent = replaceHost(htmlTemplateContent, proxyUrl.host, requestHost, requestProtocol);\n }\n\n if (isViteDevServer(server)) {\n const htmlTags: string[] = [];\n\n htmlTags.push(`<script src='/${escapeHtml(path.relative(ctx.viteConfig.root, ctx.entry))}' type='module'></script>`);\n\n const template = await server.transformIndexHtml(\n req.url,\n replaceBloggerPluginHeadComment(htmlTemplateContent, htmlTags.join('')),\n req.originalUrl,\n );\n\n res.end(template);\n } else {\n const xmlTemplateContent = fs.readFileSync(path.resolve(ctx.viteConfig.build.outDir, 'template.xml'), 'utf8');\n\n const htmlTagsStr = getBloggerPluginHeadComment(xmlTemplateContent, true);\n\n const template = replaceBloggerPluginHeadComment(htmlTemplateContent, htmlTagsStr ?? '');\n\n res.end(template);\n }\n } else if (requestHost && requestProtocol && contentType && /^(text\\/)|(application\\/(.*\\+)?(xml|json))/.test(contentType)) {\n const content = await proxyResponse.text();\n\n res.end(replaceHost(content, proxyUrl.host, requestHost, requestProtocol));\n } else {\n res.end(new Uint8Array(await proxyResponse.arrayBuffer()));\n }\n } else {\n res.statusCode = 500;\n res.statusMessage = 'Internal Server Error';\n\n res.setHeader('Content-Type', 'text/html');\n\n res.end(errorHtml(proxyUrl.href));\n }\n\n const duration = Date.now() - start;\n\n _this.info(`${req.method} ${req.originalUrl} -> ${res.statusCode} ${res.statusMessage} (${duration}ms)`);\n });\n };\n}\n\nexport default function blogger(userOptions: BloggerPluginOptions): Plugin {\n const ctx = createPluginContext(userOptions);\n\n return {\n name: 'vite-plugin-blogger',\n config(config) {\n const root = config.root || process.cwd();\n\n let entry: string | undefined;\n let template: string | undefined;\n\n if (ctx.options.entry) {\n const providedPath = path.resolve(root, ctx.options.entry);\n if (fs.existsSync(providedPath)) {\n entry = providedPath;\n } else {\n this.error(`Provided entry file does not exist: ${providedPath}`);\n }\n } else {\n for (const file of DEFAULT_ENTRIES) {\n const fullPath = path.resolve(root, 'src', file);\n if (fs.existsSync(fullPath)) {\n entry = fullPath;\n break;\n }\n }\n\n if (!entry) {\n this.error(\n 'No entry file found in \"src\".\\n' +\n `Tried: ${DEFAULT_ENTRIES.map((c) => path.join('src', c)).join(', ')}\\n` +\n '👉 Tip: You can pass a custom entry like:\\n' +\n ' blogger({ entry: \"src/my-entry.ts\" })',\n );\n }\n }\n\n if (ctx.options.template) {\n const providedPath = path.resolve(root, ctx.options.template);\n if (fs.existsSync(providedPath)) {\n template = providedPath;\n } else {\n this.error(`Provided template file does not exist: ${providedPath}`);\n }\n } else {\n for (const file of DEFAULT_TEMPLATES) {\n const fullPath = path.resolve(root, 'src', file);\n if (fs.existsSync(fullPath)) {\n template = fullPath;\n break;\n }\n }\n\n if (!template) {\n this.error(\n 'No template file found in \"src\".\\n' +\n `Tried: ${DEFAULT_TEMPLATES.map((c) => path.join('src', c)).join(', ')}\\n` +\n '👉 Tip: You can pass a custom template like:\\n' +\n ' blogger({ template: \"src/my-template.xml\" })',\n );\n }\n }\n\n // populate plugin context\n ctx.entry = entry as string;\n ctx.template = template as string;\n\n // override vite config\n config.build ??= {};\n config.build.rollupOptions ??= {};\n config.build.rollupOptions.input = entry;\n\n // remove contents between comments from template\n const xmlTemplateContent = fs.readFileSync(ctx.template, 'utf8');\n fs.writeFileSync(ctx.template, replaceBloggerPluginHeadComment(replaceBloggerPluginHeadComment(xmlTemplateContent, ''), '', true), {\n encoding: 'utf8',\n });\n },\n configResolved(config) {\n ctx.viteConfig = config;\n },\n generateBundle(_options, bundle) {\n for (const output of Object.values(bundle)) {\n if (output.type !== 'chunk' || !output.isEntry) {\n continue;\n }\n\n const xmlTemplateContent = fs.readFileSync(ctx.template, 'utf8');\n\n const htmlTags: string[] = [];\n output.viteMetadata?.importedCss.forEach((value) => {\n htmlTags.push(`<link crossorigin='anonymous' href='${escapeHtml(ctx.viteConfig.base + value)}' rel='stylesheet'/>`);\n });\n htmlTags.push(`<script crossorigin='anonymous' src='${escapeHtml(ctx.viteConfig.base + output.fileName)}' type='module'></script>`);\n\n const template = replaceBloggerPluginHeadComment(xmlTemplateContent, htmlTags.join(''), true);\n\n this.emitFile({\n type: 'asset',\n fileName: 'template.xml',\n source: template,\n });\n\n break;\n }\n },\n configureServer(server) {\n return useServerMiddleware(server, ctx, this);\n },\n configurePreviewServer(server) {\n return useServerMiddleware(server, ctx, this);\n },\n };\n}\n\nexport type { BloggerPluginOptions } from './schema';\n","import { z } from 'zod';\n\nexport const BloggerPluginOptionsSchema = z\n .object({\n entry: z.string().optional(),\n template: z.string().optional(),\n proxyBlog: z.url(),\n })\n .strict();\n\nexport type BloggerPluginOptions = z.infer<typeof BloggerPluginOptionsSchema>;\n","import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'node:http';\n\nexport function escapeHtml(str: string) {\n if (str === '') return '';\n return str.replace(/[&<>\"'`]/g, (ch) => {\n switch (ch) {\n case '&':\n return '&';\n case '<':\n return '<';\n case '>':\n return '>';\n case '\"':\n return '"';\n case \"'\":\n return ''';\n case '`':\n return '`';\n default:\n return ch;\n }\n });\n}\n\nexport function escapeRegex(str: string) {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function toWebHeaders(httpHeaders: IncomingHttpHeaders | OutgoingHttpHeaders): Headers {\n const headers = new Headers();\n for (const [name, value] of Object.entries(httpHeaders)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n headers.append(name, item);\n }\n } else {\n headers.set(name, String(value ?? ''));\n }\n }\n return headers;\n}\n\nexport function replaceBloggerPluginHeadComment(input: string, replacement: string, bcomment = false) {\n if (bcomment) {\n return input.replace(\n /<b:comment><!--blogger-plugin:head:begin--><\\/b:comment>[\\s\\S]*?<b:comment><!--blogger-plugin:head:end--><\\/b:comment>/,\n `<b:comment><!--blogger-plugin:head:begin--></b:comment>${replacement}<b:comment><!--blogger-plugin:head:end--></b:comment>`,\n );\n }\n return input.replace(\n /<!--blogger-plugin:head:begin-->[\\s\\S]*?<!--blogger-plugin:head:end-->/,\n `<!--blogger-plugin:head:begin-->${replacement}<!--blogger-plugin:head:end-->`,\n );\n}\n\nexport function getBloggerPluginHeadComment(input: string, bcomment = false) {\n if (bcomment) {\n return (\n input.match(/<b:comment><!--blogger-plugin:head:begin--><\\/b:comment>([\\s\\S]*?)<b:comment><!--blogger-plugin:head:end--><\\/b:comment>/)?.[1] ??\n null\n );\n }\n return input.match(/<!--blogger-plugin:head:begin-->([\\s\\S]*?)<!--blogger-plugin:head:end-->/)?.[1] ?? null;\n}\n\nexport function replaceHost(input: string, oldHost: string, newHost: string, newProtocol?: string) {\n return input.replace(\n new RegExp(`(https?:)?(\\\\/\\\\/|\\\\\\\\/\\\\\\\\/)${escapeRegex(oldHost)}`, 'g'),\n (_, protocol, slash) => `${protocol ? (newProtocol ?? protocol) : ''}${slash ?? ''}${newHost}`,\n );\n}\n\nexport function errorHtml(reqUrl: string) {\n return `<!DOCTYPE html>\n<html>\n\n<head>\n <meta charset='UTF-8'/>\n <meta content='width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=5, user-scalable=yes' name='viewport'/>\n <title>500 Internal Server Error</title>\n <link rel='icon' href='data:,' />\n <style>\n *, ::before, ::after {\n box-sizing: border-box;\n }\n body {\n min-height: 100svh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n margin: 0;\n padding: 20px;\n background-color: #f5f5f5;\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", Segoe UI Symbol, \"Noto Color Emoji\";\n }\n .card {\n padding: 24px;\n background-color: #ffffff;\n border: 1px solid #e5e5e5;\n max-width: 448px;\n border-radius: 14px;\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);\n display: flex;\n flex-direction: column;\n gap: 24px;\n }\n .card-content {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n .card-title {\n font-weight: 600;\n }\n .card-description {\n font-size: 14px;\n opacity: 0.85;\n }\n .card-footer {\n display: flex;\n align-items: center;\n }\n .button {\n display: inline-flex;\n white-space: nowrap;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 8px 16px;\n font-weight: 500;\n background-color: #171717;\n outline: none;\n border: none;\n color: #ffffff;\n border-radius: 8px;\n min-height: 36px;\n }\n .button:hover {\n opacity: 0.9;\n }\n .button svg {\n wiheadersdth: 16px;\n height: 16px;\n flex-shrink: 0;\n }\n .card-footer .button {\n flex-grow: 1;\n }\n </style>\n</head>\n\n<body>\n <div class='card'>\n <div class='card-content'>\n <div class='card-title'>500 Internal Server Error</div>\n <div class='card-description'>Failed to fetch: ${escapeHtml(reqUrl)}</div>\n </div>\n <div class='card-footer'>\n <button class='button' type='button'>\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-refresh-ccw\" aria-hidden=\"true\"><path d=\"M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"></path><path d=\"M3 3v5h5\"></path><path d=\"M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16\"></path><path d=\"M16 16h5v5\"></path></svg>\n Reload\n </button>\n </div>\n </div>\n <script>\n const button = document.getElementsByTagName('button')[0];\n button.addEventListener('click', () => {\n window.location.reload();\n });\n </script>\n</body>\n\n</html>`;\n}\n"],"mappings":"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","names":["_a","viewParam"]}
|
package/package.json
CHANGED
|
@@ -1,12 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blogger-plugin",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"private": false,
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"description": "A plugin which allows you to use frontend frameworks in a blogger template.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"blogger"
|
|
8
|
+
],
|
|
9
|
+
"license": "MIT",
|
|
7
10
|
"author": {
|
|
8
11
|
"name": "Deo Kumar",
|
|
9
12
|
"email": "deo@fineshopdesign.com",
|
|
10
13
|
"url": "https://github.com/kumardeo"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://github.com/kumardeo/blogger-plugin/tree/main/packages/blogger-plugin#readme",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/kumardeo/blogger-plugin",
|
|
19
|
+
"directory": "packages/blogger-plugin"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/kumardeo/blogger-plugin/issues"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"type": "module",
|
|
28
|
+
"main": "./dist/index.cjs",
|
|
29
|
+
"module": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
"./package.json": "./package.json",
|
|
33
|
+
".": {
|
|
34
|
+
"import": {
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"default": "./dist/index.js"
|
|
37
|
+
},
|
|
38
|
+
"require": {
|
|
39
|
+
"types": "./dist/index.d.cts",
|
|
40
|
+
"default": "./dist/index.cjs"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"./vite": {
|
|
44
|
+
"import": {
|
|
45
|
+
"types": "./dist/vite.d.ts",
|
|
46
|
+
"default": "./dist/vite.js"
|
|
47
|
+
},
|
|
48
|
+
"require": {
|
|
49
|
+
"types": "./dist/vite.d.cts",
|
|
50
|
+
"default": "./dist/vite.cjs"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"vite": "^7.0.0"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"zod": "^4.1.11"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/node": "^24.6.2",
|
|
62
|
+
"tsup": "^8.5.0",
|
|
63
|
+
"vite": "^7.0.0"
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"lint": "biome lint ./src",
|
|
67
|
+
"check": "biome check ./src",
|
|
68
|
+
"check:types": "tsc --noEmit",
|
|
69
|
+
"build": "NODE_ENV=production tsup",
|
|
70
|
+
"dev": "NODE_ENV=development tsup --watch"
|
|
11
71
|
}
|
|
12
72
|
}
|