diff --git a/docs/README.md b/docs/README.md
index b5eb241..b171988 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,4 +1,4 @@
# vite-plugin-multip docs
Documentation of the plugin (web version in arrtive) vite-plugin-multip
-- [custom html](https://github.com/vclemenzi/vite-plugin-multip/blob/main/docs/custom-html.md)
+- [layouts](https://github.com/vclemenzi/vite-plugin-multip/blob/main/docs/layouts.md)
diff --git a/docs/custom-html.md b/docs/custom-html.md
deleted file mode 100644
index 872360b..0000000
--- a/docs/custom-html.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# HTML Customization with vite-plugin-multip
-
-With the `vite-plugin-multip` plugin, you have the ability to fully customize the HTML structure using a custom HTML template.
-
-Configuration:
-```ts
-multipage({ customHtml: "path/to/your/template.html" })
-```
-
-Example of the custom HTML template:
-```html
-
-
-
-
-
-
- My Custom HTML
-
-
- {% body %}
-
-
-```
-
-`{% body %}` will be replaced with the content of the specific page's body. This feature allows you to completely tailor the appearance and structure of your multipage setup, offering greater flexibility in design.
-
-*You can find an example [here](https://github.com/vclemenzi/vite-plugin-multip/tree/main/examples/custom-html)*
diff --git a/docs/layouts.md b/docs/layouts.md
new file mode 100644
index 0000000..95fc26e
--- /dev/null
+++ b/docs/layouts.md
@@ -0,0 +1,65 @@
+## Layouts with vite-plugin-multip
+
+When utilizing the `vite-plugin-multip` plugin, you gain the capability to finely tailor the structure and appearance of your pages by employing custom layouts. This functionality empowers you to craft distinct layouts for various pages or groups of pages, thereby enhancing the flexibility and customization options for your multipage application.
+
+### Custom Layout Example
+
+Below is a minimalist illustration of a custom layout file, `layout.html`, showcasing the fundamental structure:
+
+```html
+
+
+
+
+
+ Custom Layout
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+In this example:
+
+- The `layout.html` file contains a basic HTML structure with a header, a main section (where the specific page content will be inserted), and a footer.
+- The ` ` tag indicates where the content of the specific page will be inserted into the layout.
+- This layout can be further customized by adding CSS styles, JavaScript scripts, or other HTML elements according to the specific project requirements.
+
+### Layout Structure
+
+Each page in your application can utilize its own layout, and layouts are resolved based on proximity. Here's an example directory structure:
+
+```bash
+pages/
+ layout.html # This layout is named "1"
+ index.svelte # Uses layout "1"
+ foo/
+ index.svelte # Uses layout "1"
+ hello/
+ layout.html # This layout is named "2"
+ index.svelte # Uses layout "2"
+ world/
+ index.svelte # Uses layout "2"
+```
+
+In this structure:
+
+- Pages located closer to a specific layout file will use that layout.
+- For instance, `index.svelte` and `foo/index.svelte` will both use the layout defined in `layout.html` because it's the nearest layout file.
+- Pages within the `hello` directory and its subdirectories will use the layout defined in `hello/layout.html`.
+
+This approach allows you to organize your layouts and pages logically and apply different layouts as needed throughout your application.
+
+For an example of layout usage with `vite-plugin-multip`, you can refer to the official plugin repository on GitHub at the following link: [https://github.com/vclemenzi/vite-plugin-multip/tree/main/examples/layouts](https://github.com/vclemenzi/vite-plugin-multip/tree/main/examples/layouts).
diff --git a/examples/custom-html/custom.html b/examples/custom-html/custom.html
deleted file mode 100644
index d122684..0000000
--- a/examples/custom-html/custom.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
- My Custom HTML
-
-
-
- {% body %}
-
-
-
diff --git a/examples/custom-html/src/pages/index.svelte b/examples/custom-html/src/pages/index.svelte
deleted file mode 100644
index f78f758..0000000
--- a/examples/custom-html/src/pages/index.svelte
+++ /dev/null
@@ -1 +0,0 @@
-Custom HTML
diff --git a/examples/custom-html/vite.config.ts.timestamp-1710927809121-4e20fe6d4f043.mjs b/examples/custom-html/vite.config.ts.timestamp-1710927809121-4e20fe6d4f043.mjs
deleted file mode 100644
index 147397a..0000000
--- a/examples/custom-html/vite.config.ts.timestamp-1710927809121-4e20fe6d4f043.mjs
+++ /dev/null
@@ -1,202 +0,0 @@
-// vite.config.ts
-import { defineConfig } from "file:///home/vc/Documents/vite-multipage/examples/custom-html/node_modules/.pnpm/vite@5.2.0/node_modules/vite/dist/node/index.js";
-import { svelte as svelte2 } from "file:///home/vc/Documents/vite-multipage/examples/custom-html/node_modules/.pnpm/@sveltejs+vite-plugin-svelte@3.0.2_svelte@4.2.12_vite@5.2.0/node_modules/@sveltejs/vite-plugin-svelte/src/index.js";
-
-// ../../src/index.ts
-import { normalizePath } from "file:///home/vc/Documents/vite-multipage/node_modules/.pnpm/vite@5.1.6_@types+node@20.11.27/node_modules/vite/dist/node/index.js";
-import glob from "file:///home/vc/Documents/vite-multipage/node_modules/.pnpm/fast-glob@3.3.2/node_modules/fast-glob/out/index.js";
-
-// ../../src/boilerplate/frameworks/react.ts
-var react = (file) => {
- return `
-
-
- `;
-};
-
-// ../../src/boilerplate/frameworks/svelte.ts
-var svelte = (file) => {
- return `
-
-
- `;
-};
-
-// ../../src/boilerplate/frameworks/vue.ts
-var vue = (file) => {
- return `
-
-
- `;
-};
-
-// ../../src/boilerplate/html.ts
-import { minify } from "file:///home/vc/Documents/vite-multipage/node_modules/.pnpm/html-minifier-terser@7.2.0/node_modules/html-minifier-terser/src/htmlminifier.js";
-var html = async (body, config) => {
- let code = `
-
-
-
-
-
-
-
-
- ${body}
-
- `;
- if (config?.customHtml) {
- console.log("customHtml");
- code = config.customHtml.replace("{% body %}", body);
- }
- const result = await minify(code, {
- collapseWhitespace: config?.minify?.collapseWhitespace || true,
- removeComments: config?.minify?.removeComments || true,
- ...config?.minify
- });
- return result;
-};
-
-// ../../src/boilerplate/index.ts
-var generateBoilerplate = async (file, framework, config) => {
- switch (framework) {
- case "svelte":
- return await html(svelte(file), config);
- case "vue":
- return await html(vue(file), config);
- case "tsx":
- return await html(react(file), config);
- default:
- return "";
- }
- ;
-};
-
-// ../../src/index.ts
-import { dirname, resolve } from "path";
-
-// ../../src/server/create.ts
-import fs from "fs";
-import mime from "file:///home/vc/Documents/vite-multipage/node_modules/.pnpm/mime@4.0.1/node_modules/mime/dist/src/index.js";
-
-// ../../src/server/hot.ts
-import { exec } from "child_process";
-var hotupdate = () => {
- exec("npx vite build --mode development", (err) => {
- if (err) {
- console.error(err);
- return;
- }
- const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
- console.log(
- `\x1B[2m${timestamp}\x1B[32m [vite-plugin-multip]\x1B[0m Build completed`
- );
- });
-};
-
-// ../../src/server/create.ts
-var createServer = (server) => {
- hotupdate();
- server.middlewares.use((req, res) => {
- if (!req.url)
- return;
- if (!/\.[a-z]+$/.test(req.url)) {
- return res.end(fs.readFileSync(`dist${req.url}/index.html`));
- }
- const ext = req.url.split(".").pop() || "";
- res.setHeader("Content-Type", mime.getType(ext) || "text/plain");
- return res.end(fs.readFileSync(`dist${req.url}`));
- });
-};
-
-// ../../src/index.ts
-var multipage = (config) => {
- const root = config?.directory || "src/pages";
- let framework = config?.framework || "";
- return {
- name: "vite-plugin-multi-page",
- config: () => {
- const pages = glob.sync("**/*.{svelte,vue,tsx,jsx}", {
- cwd: root,
- onlyFiles: true
- });
- const entries = pages.map((page) => {
- if (!framework)
- framework = page.split(".").pop() || "";
- const name = dirname(page);
- if (name === "." || !name)
- return "index";
- return name;
- });
- const input = entries.reduce((acc, page) => {
- const fileName = "index.html";
- if (page === "index") {
- acc[page] = resolve(root, fileName);
- return acc;
- }
- acc[page] = resolve(root, page, fileName);
- return acc;
- }, {});
- return {
- root,
- appType: "custom",
- build: {
- outDir: "dist",
- rollupOptions: {
- input,
- output: {
- format: "es",
- strict: false,
- entryFileNames: "assets/[name]-[hash].js",
- chunkFileNames: "assets/[name]-[hash].js",
- assetFileNames: "assets/[name]-[hash].[ext]",
- dir: "dist/"
- }
- }
- }
- };
- },
- resolveId(id) {
- return id.includes("index.html") ? id : null;
- },
- async load(id) {
- if (framework === "")
- throw new Error("Framework not found");
- const fileName = "index.html";
- if (!id.endsWith(fileName))
- return null;
- id = normalizePath(id);
- const page = id.replace(fileName, `index.${framework}`);
- return await generateBoilerplate(page, framework, config || {});
- },
- configureServer: createServer,
- handleHotUpdate: hotupdate
- };
-};
-
-// vite.config.ts
-var vite_config_default = defineConfig({
- plugins: [svelte2(), multipage()]
-});
-export {
- vite_config_default as default
-};
-//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiLCAiLi4vLi4vc3JjL2luZGV4LnRzIiwgIi4uLy4uL3NyYy9ib2lsZXJwbGF0ZS9mcmFtZXdvcmtzL3JlYWN0LnRzIiwgIi4uLy4uL3NyYy9ib2lsZXJwbGF0ZS9mcmFtZXdvcmtzL3N2ZWx0ZS50cyIsICIuLi8uLi9zcmMvYm9pbGVycGxhdGUvZnJhbWV3b3Jrcy92dWUudHMiLCAiLi4vLi4vc3JjL2JvaWxlcnBsYXRlL2h0bWwudHMiLCAiLi4vLi4vc3JjL2JvaWxlcnBsYXRlL2luZGV4LnRzIiwgIi4uLy4uL3NyYy9zZXJ2ZXIvY3JlYXRlLnRzIiwgIi4uLy4uL3NyYy9zZXJ2ZXIvaG90LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL2hvbWUvdmMvRG9jdW1lbnRzL3ZpdGUtbXVsdGlwYWdlL2V4YW1wbGVzL2N1c3RvbS1odG1sXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCIvaG9tZS92Yy9Eb2N1bWVudHMvdml0ZS1tdWx0aXBhZ2UvZXhhbXBsZXMvY3VzdG9tLWh0bWwvdml0ZS5jb25maWcudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvdmMvRG9jdW1lbnRzL3ZpdGUtbXVsdGlwYWdlL2V4YW1wbGVzL2N1c3RvbS1odG1sL3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZGVmaW5lQ29uZmlnIH0gZnJvbSAndml0ZSdcbmltcG9ydCB7IHN2ZWx0ZSB9IGZyb20gJ0BzdmVsdGVqcy92aXRlLXBsdWdpbi1zdmVsdGUnXG5pbXBvcnQgeyBtdWx0aXBhZ2UgfSBmcm9tICcuLi8uLi9zcmMvaW5kZXgnXG5cbi8vIGh0dHBzOi8vdml0ZWpzLmRldi9jb25maWcvXG5leHBvcnQgZGVmYXVsdCBkZWZpbmVDb25maWcoe1xuICBwbHVnaW5zOiBbc3ZlbHRlKCksIG11bHRpcGFnZSgpXSxcbn0pXG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvaW5kZXgudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvdmMvRG9jdW1lbnRzL3ZpdGUtbXVsdGlwYWdlL3NyYy9pbmRleC50c1wiO2ltcG9ydCB7IG5vcm1hbGl6ZVBhdGgsIHR5cGUgUGx1Z2luIH0gZnJvbSBcInZpdGVcIjtcbmltcG9ydCB0eXBlIHsgQ29uZmlnIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCBnbG9iIGZyb20gXCJmYXN0LWdsb2JcIjtcbmltcG9ydCB7IGdlbmVyYXRlQm9pbGVycGxhdGUgfSBmcm9tIFwiLi9ib2lsZXJwbGF0ZVwiO1xuaW1wb3J0IHsgZGlybmFtZSwgcmVzb2x2ZSB9IGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBjcmVhdGVTZXJ2ZXIgfSBmcm9tIFwiLi9zZXJ2ZXIvY3JlYXRlXCI7XG5pbXBvcnQgeyBob3R1cGRhdGUgfSBmcm9tIFwiLi9zZXJ2ZXIvaG90XCI7XG5cbmV4cG9ydCBjb25zdCBtdWx0aXBhZ2UgPSAoY29uZmlnPzogQ29uZmlnKTogUGx1Z2luID0+IHtcbiAgY29uc3Qgcm9vdCA9IGNvbmZpZz8uZGlyZWN0b3J5IHx8IFwic3JjL3BhZ2VzXCI7XG4gIGxldCBmcmFtZXdvcmsgPSBjb25maWc/LmZyYW1ld29yayB8fCBcIlwiO1xuXG4gIHJldHVybiB7XG4gICAgbmFtZTogXCJ2aXRlLXBsdWdpbi1tdWx0aS1wYWdlXCIsXG4gICAgY29uZmlnOiAoKSA9PiB7XG4gICAgICBjb25zdCBwYWdlcyA9IGdsb2Iuc3luYyhcIioqLyoue3N2ZWx0ZSx2dWUsdHN4LGpzeH1cIiwge1xuICAgICAgICBjd2Q6IHJvb3QsXG4gICAgICAgIG9ubHlGaWxlczogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBlbnRyaWVzID0gcGFnZXMubWFwKChwYWdlKSA9PiB7XG4gICAgICAgIC8vIEdldCBmcmFtZXdvcmsgZnJvbSBmaWxlIGV4dGVuc2lvblxuICAgICAgICBpZiAoIWZyYW1ld29yaykgZnJhbWV3b3JrID0gcGFnZS5zcGxpdChcIi5cIikucG9wKCkgfHwgXCJcIjtcblxuICAgICAgICBjb25zdCBuYW1lID0gZGlybmFtZShwYWdlKTtcblxuICAgICAgICBpZiAobmFtZSA9PT0gXCIuXCIgfHwgIW5hbWUpIHJldHVybiBcImluZGV4XCI7XG5cbiAgICAgICAgcmV0dXJuIG5hbWU7XG4gICAgICB9KTtcblxuICAgICAgY29uc3QgaW5wdXQgPSBlbnRyaWVzLnJlZHVjZSgoYWNjOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LCBwYWdlKSA9PiB7XG4gICAgICAgIGNvbnN0IGZpbGVOYW1lID0gXCJpbmRleC5odG1sXCI7XG5cbiAgICAgICAgaWYgKHBhZ2UgPT09IFwiaW5kZXhcIikge1xuICAgICAgICAgIGFjY1twYWdlXSA9IHJlc29sdmUocm9vdCwgZmlsZU5hbWUpO1xuICAgICAgICAgIHJldHVybiBhY2M7XG4gICAgICAgIH1cblxuICAgICAgICBhY2NbcGFnZV0gPSByZXNvbHZlKHJvb3QsIHBhZ2UsIGZpbGVOYW1lKTtcblxuICAgICAgICByZXR1cm4gYWNjO1xuICAgICAgfSwge30pO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICByb290LFxuICAgICAgICBhcHBUeXBlOiBcImN1c3RvbVwiLFxuICAgICAgICBidWlsZDoge1xuICAgICAgICAgIG91dERpcjogXCJkaXN0XCIsXG4gICAgICAgICAgcm9sbHVwT3B0aW9uczoge1xuICAgICAgICAgICAgaW5wdXQsXG4gICAgICAgICAgICBvdXRwdXQ6IHtcbiAgICAgICAgICAgICAgZm9ybWF0OiBcImVzXCIsXG4gICAgICAgICAgICAgIHN0cmljdDogZmFsc2UsXG4gICAgICAgICAgICAgIGVudHJ5RmlsZU5hbWVzOiBcImFzc2V0cy9bbmFtZV0tW2hhc2hdLmpzXCIsXG4gICAgICAgICAgICAgIGNodW5rRmlsZU5hbWVzOiBcImFzc2V0cy9bbmFtZV0tW2hhc2hdLmpzXCIsXG4gICAgICAgICAgICAgIGFzc2V0RmlsZU5hbWVzOiBcImFzc2V0cy9bbmFtZV0tW2hhc2hdLltleHRdXCIsXG4gICAgICAgICAgICAgIGRpcjogXCJkaXN0L1wiLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9LFxuXG4gICAgcmVzb2x2ZUlkKGlkKSB7XG4gICAgICByZXR1cm4gaWQuaW5jbHVkZXMoXCJpbmRleC5odG1sXCIpID8gaWQgOiBudWxsO1xuICAgIH0sXG5cbiAgICBhc3luYyBsb2FkKGlkKSB7XG4gICAgICBpZiAoZnJhbWV3b3JrID09PSBcIlwiKSB0aHJvdyBuZXcgRXJyb3IoXCJGcmFtZXdvcmsgbm90IGZvdW5kXCIpO1xuXG4gICAgICBjb25zdCBmaWxlTmFtZSA9IFwiaW5kZXguaHRtbFwiO1xuXG4gICAgICBpZiAoIWlkLmVuZHNXaXRoKGZpbGVOYW1lKSkgcmV0dXJuIG51bGw7XG5cbiAgICAgIGlkID0gbm9ybWFsaXplUGF0aChpZCk7XG5cbiAgICAgIGNvbnN0IHBhZ2UgPSBpZC5yZXBsYWNlKGZpbGVOYW1lLCBgaW5kZXguJHtmcmFtZXdvcmt9YCk7XG5cbiAgICAgIHJldHVybiBhd2FpdCBnZW5lcmF0ZUJvaWxlcnBsYXRlKHBhZ2UsIGZyYW1ld29yaywgY29uZmlnIHx8IHt9KVxuICAgIH0sXG5cbiAgICBjb25maWd1cmVTZXJ2ZXI6IGNyZWF0ZVNlcnZlcixcbiAgICBoYW5kbGVIb3RVcGRhdGU6IGhvdHVwZGF0ZSxcbiAgfTtcbn07XG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvYm9pbGVycGxhdGUvZnJhbWV3b3Jrc1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9maWxlbmFtZSA9IFwiL2hvbWUvdmMvRG9jdW1lbnRzL3ZpdGUtbXVsdGlwYWdlL3NyYy9ib2lsZXJwbGF0ZS9mcmFtZXdvcmtzL3JlYWN0LnRzXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ltcG9ydF9tZXRhX3VybCA9IFwiZmlsZTovLy9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvYm9pbGVycGxhdGUvZnJhbWV3b3Jrcy9yZWFjdC50c1wiO2V4cG9ydCBjb25zdCByZWFjdCA9IChmaWxlOiBzdHJpbmcpOiBzdHJpbmcgPT4ge1xuICByZXR1cm4gYFxuICAgIDxkaXYgaWQ9XCJhcHBcIj48L2Rpdj5cbiAgICA8c2NyaXB0IHR5cGU9XCJtb2R1bGVcIj5cbiAgICAgIGltcG9ydCBSZWFjdCBmcm9tICdyZWFjdCc7XG4gICAgICBpbXBvcnQgUmVhY3RET00gZnJvbSAncmVhY3QtZG9tL2NsaWVudCc7XG4gICAgICBpbXBvcnQgQXBwIGZyb20gJyR7ZmlsZX0nO1xuXG4gICAgICBjb25zdCBlID0gUmVhY3QuY3JlYXRlRWxlbWVudDtcblxuICAgICAgUmVhY3RET00uY3JlYXRlUm9vdChkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYXBwJykpLnJlbmRlcihcbiAgICAgICAgZShBcHAsIG51bGwpXG4gICAgICApO1xuICAgIDwvc2NyaXB0PlxuICBgO1xufVxuIiwgImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS92Yy9Eb2N1bWVudHMvdml0ZS1tdWx0aXBhZ2Uvc3JjL2JvaWxlcnBsYXRlL2ZyYW1ld29ya3NcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvYm9pbGVycGxhdGUvZnJhbWV3b3Jrcy9zdmVsdGUudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvdmMvRG9jdW1lbnRzL3ZpdGUtbXVsdGlwYWdlL3NyYy9ib2lsZXJwbGF0ZS9mcmFtZXdvcmtzL3N2ZWx0ZS50c1wiO2V4cG9ydCBjb25zdCBzdmVsdGUgPSAoZmlsZTogc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgcmV0dXJuIGBcbiAgICA8ZGl2IGlkPVwiYXBwXCI+PC9kaXY+XG4gICAgPHNjcmlwdCB0eXBlPVwibW9kdWxlXCI+XG4gICAgICBpbXBvcnQgQXBwIGZyb20gJyR7ZmlsZX0nO1xuICAgICAgY29uc3QgYXBwID0gbmV3IEFwcCh7IHRhcmdldDogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2FwcCcpIH0pO1xuICAgICAgZXhwb3J0IGRlZmF1bHQgYXBwO1xuICAgIDwvc2NyaXB0PlxuICBgO1xufVxuIiwgImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCIvaG9tZS92Yy9Eb2N1bWVudHMvdml0ZS1tdWx0aXBhZ2Uvc3JjL2JvaWxlcnBsYXRlL2ZyYW1ld29ya3NcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvYm9pbGVycGxhdGUvZnJhbWV3b3Jrcy92dWUudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvdmMvRG9jdW1lbnRzL3ZpdGUtbXVsdGlwYWdlL3NyYy9ib2lsZXJwbGF0ZS9mcmFtZXdvcmtzL3Z1ZS50c1wiO2V4cG9ydCBjb25zdCB2dWUgPSAoZmlsZTogc3RyaW5nKTogc3RyaW5nID0+IHtcbiAgcmV0dXJuIGBcbiAgICA8ZGl2IGlkPVwiYXBwXCI+PC9kaXY+XG4gICAgPHNjcmlwdCB0eXBlPVwibW9kdWxlXCI+XG4gICAgICBpbXBvcnQgeyBjcmVhdGVBcHAgfSBmcm9tICd2dWUnO1xuICAgICAgaW1wb3J0IEFwcCBmcm9tICcke2ZpbGV9JztcbiAgICAgIGNyZWF0ZUFwcChBcHApLm1vdW50KCcjYXBwJyk7XG4gICAgPC9zY3JpcHQ+XG4gIGA7XG59XG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvYm9pbGVycGxhdGVcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvYm9pbGVycGxhdGUvaHRtbC50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vaG9tZS92Yy9Eb2N1bWVudHMvdml0ZS1tdWx0aXBhZ2Uvc3JjL2JvaWxlcnBsYXRlL2h0bWwudHNcIjtpbXBvcnQgeyBtaW5pZnkgfSBmcm9tIFwiaHRtbC1taW5pZmllci10ZXJzZXJcIjtcbmltcG9ydCB0eXBlIHsgQ29uZmlnIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5cbmV4cG9ydCBjb25zdCBodG1sID0gYXN5bmMgKGJvZHk6IHN0cmluZywgY29uZmlnPzogQ29uZmlnKTogUHJvbWlzZTxzdHJpbmc+ID0+IHtcbiAgbGV0IGNvZGUgPSBgXG4gICAgICA8IURPQ1RZUEUgaHRtbD5cbiAgICAgIDxodG1sIGxhbmc9XCJlblwiPlxuICAgICAgICA8aGVhZD5cbiAgICAgICAgICA8bWV0YSBjaGFyc2V0PVwiVVRGLThcIiAvPlxuICAgICAgICAgIDxtZXRhIG5hbWU9XCJ2aWV3cG9ydFwiIGNvbnRlbnQ9XCJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MS4wXCIgLz5cbiAgICAgICAgICA8dGl0bGU+PC90aXRsZT5cbiAgICAgICAgPC9oZWFkPlxuICAgICAgICA8Ym9keT5cbiAgICAgICAgICAke2JvZHl9XG4gICAgICAgIDwvYm9keT5cbiAgICAgIDwvaHRtbD5gO1xuXG4gIGlmIChjb25maWc/LmN1c3RvbUh0bWwpIHtcbiAgICBjb25zb2xlLmxvZyhcImN1c3RvbUh0bWxcIik7XG4gICAgY29kZSA9IGNvbmZpZy5jdXN0b21IdG1sLnJlcGxhY2UoXCJ7JSBib2R5ICV9XCIsIGJvZHkpO1xuICB9XG5cbiAgY29uc3QgcmVzdWx0ID0gYXdhaXQgbWluaWZ5KGNvZGUsIHtcbiAgICBjb2xsYXBzZVdoaXRlc3BhY2U6IGNvbmZpZz8ubWluaWZ5Py5jb2xsYXBzZVdoaXRlc3BhY2UgfHwgdHJ1ZSxcbiAgICByZW1vdmVDb21tZW50czogY29uZmlnPy5taW5pZnk/LnJlbW92ZUNvbW1lbnRzIHx8IHRydWUsXG4gICAgLi4uY29uZmlnPy5taW5pZnksXG4gIH0pO1xuXG4gIHJldHVybiByZXN1bHQ7XG59XG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvYm9pbGVycGxhdGVcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvYm9pbGVycGxhdGUvaW5kZXgudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvdmMvRG9jdW1lbnRzL3ZpdGUtbXVsdGlwYWdlL3NyYy9ib2lsZXJwbGF0ZS9pbmRleC50c1wiO2ltcG9ydCB0eXBlIHsgQ29uZmlnIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5pbXBvcnQgeyByZWFjdCB9IGZyb20gXCIuL2ZyYW1ld29ya3MvcmVhY3RcIjtcbmltcG9ydCB7IHN2ZWx0ZSB9IGZyb20gXCIuL2ZyYW1ld29ya3Mvc3ZlbHRlXCI7XG5pbXBvcnQgeyB2dWUgfSBmcm9tIFwiLi9mcmFtZXdvcmtzL3Z1ZVwiO1xuaW1wb3J0IHsgaHRtbCB9IGZyb20gXCIuL2h0bWxcIjtcblxuZXhwb3J0IGNvbnN0IGdlbmVyYXRlQm9pbGVycGxhdGUgPSBhc3luYyAoZmlsZTogc3RyaW5nLCBmcmFtZXdvcms6IHN0cmluZywgY29uZmlnOiBDb25maWcpOiBQcm9taXNlPHN0cmluZz4gPT4ge1xuICBzd2l0Y2ggKGZyYW1ld29yaykge1xuICAgIGNhc2UgXCJzdmVsdGVcIjpcbiAgICAgIHJldHVybiBhd2FpdCBodG1sKHN2ZWx0ZShmaWxlKSwgY29uZmlnKTtcbiAgICBjYXNlIFwidnVlXCI6XG4gICAgICByZXR1cm4gYXdhaXQgaHRtbCh2dWUoZmlsZSksIGNvbmZpZyk7XG4gICAgY2FzZSBcInRzeFwiIHx8IFwianN4XCI6XG4gICAgICByZXR1cm4gYXdhaXQgaHRtbChyZWFjdChmaWxlKSwgY29uZmlnKTtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIFwiXCI7XG4gIH07XG59XG4iLCAiY29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2Rpcm5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvc2VydmVyXCI7Y29uc3QgX192aXRlX2luamVjdGVkX29yaWdpbmFsX2ZpbGVuYW1lID0gXCIvaG9tZS92Yy9Eb2N1bWVudHMvdml0ZS1tdWx0aXBhZ2Uvc3JjL3NlcnZlci9jcmVhdGUudHNcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfaW1wb3J0X21ldGFfdXJsID0gXCJmaWxlOi8vL2hvbWUvdmMvRG9jdW1lbnRzL3ZpdGUtbXVsdGlwYWdlL3NyYy9zZXJ2ZXIvY3JlYXRlLnRzXCI7aW1wb3J0IHR5cGUgeyBWaXRlRGV2U2VydmVyIH0gZnJvbSBcInZpdGVcIjtcbmltcG9ydCBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCBtaW1lIGZyb20gXCJtaW1lXCI7XG5pbXBvcnQgeyBob3R1cGRhdGUgfSBmcm9tIFwiLi9ob3RcIjtcblxuLy8gVGhpcyBmZWF0dXJlIGlzIGluIGJldGEsIHNvIGl0IG1heSBub3Qgd29yayBhcyBleHBlY3RlZFxuLy8gSSBob3BlIEknbGwgZmluZCBhIGJldHRlciB3YXkgdG8gZG8gdGhpc1xuLy8gQXMgdG9kYXksIGRldiBzZXJ2ZXIgZG8gdGhlIHNhbWUgdGhpbmcgYXMgcHJldmlldyBzZXJ2ZXJcblxuZXhwb3J0IGNvbnN0IGNyZWF0ZVNlcnZlciA9IChzZXJ2ZXI6IFZpdGVEZXZTZXJ2ZXIpID0+IHtcbiAgaG90dXBkYXRlKCk7XG5cbiAgc2VydmVyLm1pZGRsZXdhcmVzLnVzZSgocmVxLCByZXMpID0+IHtcbiAgICBpZiAoIXJlcS51cmwpIHJldHVybjtcblxuICAgIGlmICghL1xcLlthLXpdKyQvLnRlc3QocmVxLnVybCkpIHtcbiAgICAgIHJldHVybiByZXMuZW5kKGZzLnJlYWRGaWxlU3luYyhgZGlzdCR7cmVxLnVybH0vaW5kZXguaHRtbGApKTtcbiAgICB9XG5cbiAgICBjb25zdCBleHQgPSByZXEudXJsLnNwbGl0KFwiLlwiKS5wb3AoKSB8fCBcIlwiO1xuXG4gICAgcmVzLnNldEhlYWRlcihcIkNvbnRlbnQtVHlwZVwiLCBtaW1lLmdldFR5cGUoZXh0KSB8fCBcInRleHQvcGxhaW5cIik7XG4gICAgcmV0dXJuIHJlcy5lbmQoZnMucmVhZEZpbGVTeW5jKGBkaXN0JHtyZXEudXJsfWApKTtcbiAgfSk7XG59OztcbiIsICJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL2hvbWUvdmMvRG9jdW1lbnRzL3ZpdGUtbXVsdGlwYWdlL3NyYy9zZXJ2ZXJcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9ob21lL3ZjL0RvY3VtZW50cy92aXRlLW11bHRpcGFnZS9zcmMvc2VydmVyL2hvdC50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vaG9tZS92Yy9Eb2N1bWVudHMvdml0ZS1tdWx0aXBhZ2Uvc3JjL3NlcnZlci9ob3QudHNcIjtpbXBvcnQgeyBleGVjIH0gZnJvbSBcImNoaWxkX3Byb2Nlc3NcIjtcblxuZXhwb3J0IGNvbnN0IGhvdHVwZGF0ZSA9ICgpID0+IHtcbiAgZXhlYyhcIm5weCB2aXRlIGJ1aWxkIC0tbW9kZSBkZXZlbG9wbWVudFwiLCAoZXJyKSA9PiB7XG4gICAgaWYgKGVycikge1xuICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRpbWVzdGFtcCA9IG5ldyBEYXRlKCkudG9Mb2NhbGVUaW1lU3RyaW5nKCk7XG4gICAgY29uc29sZS5sb2coXG4gICAgICBgXFx4MWJbMm0ke3RpbWVzdGFtcH1cXHgxYlszMm0gW3ZpdGUtcGx1Z2luLW11bHRpcF1cXHgxYlswbSBCdWlsZCBjb21wbGV0ZWRgXG4gICAgKTtcbiAgfSk7XG59O1xuIl0sCiAgIm1hcHBpbmdzIjogIjtBQUFvVixTQUFTLG9CQUFvQjtBQUNqWCxTQUFTLFVBQUFBLGVBQWM7OztBQ0Q4UCxTQUFTLHFCQUFrQztBQUVoVSxPQUFPLFVBQVU7OztBQ0ZnVixJQUFNLFFBQVEsQ0FBQyxTQUF5QjtBQUN2WSxTQUFPO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSx5QkFLZ0IsSUFBSTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFTN0I7OztBQ2ZtVyxJQUFNLFNBQVMsQ0FBQyxTQUF5QjtBQUMxWSxTQUFPO0FBQUE7QUFBQTtBQUFBLHlCQUdnQixJQUFJO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFLN0I7OztBQ1Q2VixJQUFNLE1BQU0sQ0FBQyxTQUF5QjtBQUNqWSxTQUFPO0FBQUE7QUFBQTtBQUFBO0FBQUEseUJBSWdCLElBQUk7QUFBQTtBQUFBO0FBQUE7QUFJN0I7OztBQ1R1VCxTQUFTLGNBQWM7QUFHdlUsSUFBTSxPQUFPLE9BQU8sTUFBYyxX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
diff --git a/examples/custom-html/.gitignore b/examples/layouts/.gitignore
similarity index 100%
rename from examples/custom-html/.gitignore
rename to examples/layouts/.gitignore
diff --git a/examples/custom-html/.vscode/extensions.json b/examples/layouts/.vscode/extensions.json
similarity index 100%
rename from examples/custom-html/.vscode/extensions.json
rename to examples/layouts/.vscode/extensions.json
diff --git a/examples/custom-html/README.md b/examples/layouts/README.md
similarity index 100%
rename from examples/custom-html/README.md
rename to examples/layouts/README.md
diff --git a/examples/layouts/index.html b/examples/layouts/index.html
new file mode 100644
index 0000000..b6c5f0a
--- /dev/null
+++ b/examples/layouts/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Vite + Svelte + TS
+
+
+
+
+
+
diff --git a/examples/custom-html/package.json b/examples/layouts/package.json
similarity index 84%
rename from examples/custom-html/package.json
rename to examples/layouts/package.json
index 304c19c..d04384c 100644
--- a/examples/custom-html/package.json
+++ b/examples/layouts/package.json
@@ -1,5 +1,5 @@
{
- "name": "custom-html",
+ "name": "layouts",
"private": true,
"version": "0.0.0",
"type": "module",
@@ -13,9 +13,9 @@
"@sveltejs/vite-plugin-svelte": "^3.0.2",
"@tsconfig/svelte": "^5.0.2",
"svelte": "^4.2.12",
- "svelte-check": "^3.6.6",
+ "svelte-check": "^3.6.7",
"tslib": "^2.6.2",
"typescript": "^5.2.2",
- "vite": "^5.1.6"
+ "vite": "^5.2.0"
}
}
diff --git a/examples/custom-html/pnpm-lock.yaml b/examples/layouts/pnpm-lock.yaml
similarity index 97%
rename from examples/custom-html/pnpm-lock.yaml
rename to examples/layouts/pnpm-lock.yaml
index 775f353..534bb8a 100644
--- a/examples/custom-html/pnpm-lock.yaml
+++ b/examples/layouts/pnpm-lock.yaml
@@ -7,7 +7,7 @@ settings:
devDependencies:
'@sveltejs/vite-plugin-svelte':
specifier: ^3.0.2
- version: 3.0.2(svelte@4.2.12)(vite@5.2.0)
+ version: 3.0.2(svelte@4.2.12)(vite@5.2.2)
'@tsconfig/svelte':
specifier: ^5.0.2
version: 5.0.2
@@ -15,17 +15,17 @@ devDependencies:
specifier: ^4.2.12
version: 4.2.12
svelte-check:
- specifier: ^3.6.6
+ specifier: ^3.6.7
version: 3.6.8(svelte@4.2.12)
tslib:
specifier: ^2.6.2
version: 2.6.2
typescript:
specifier: ^5.2.2
- version: 5.4.2
+ version: 5.4.3
vite:
- specifier: ^5.1.6
- version: 5.2.0
+ specifier: ^5.2.0
+ version: 5.2.2
packages:
@@ -399,7 +399,7 @@ packages:
dev: true
optional: true
- /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.0):
+ /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.2):
resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==}
engines: {node: ^18.0.0 || >=20}
peerDependencies:
@@ -407,30 +407,30 @@ packages:
svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.0
dependencies:
- '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.12)(vite@5.2.0)
+ '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.12)(vite@5.2.2)
debug: 4.3.4
svelte: 4.2.12
- vite: 5.2.0
+ vite: 5.2.2
transitivePeerDependencies:
- supports-color
dev: true
- /@sveltejs/vite-plugin-svelte@3.0.2(svelte@4.2.12)(vite@5.2.0):
+ /@sveltejs/vite-plugin-svelte@3.0.2(svelte@4.2.12)(vite@5.2.2):
resolution: {integrity: sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==}
engines: {node: ^18.0.0 || >=20}
peerDependencies:
svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.0
dependencies:
- '@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.0)
+ '@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.2)
debug: 4.3.4
deepmerge: 4.3.1
kleur: 4.1.5
magic-string: 0.30.8
svelte: 4.2.12
svelte-hmr: 0.15.3(svelte@4.2.12)
- vite: 5.2.0
- vitefu: 0.2.5(vite@5.2.0)
+ vite: 5.2.2
+ vitefu: 0.2.5(vite@5.2.2)
transitivePeerDependencies:
- supports-color
dev: true
@@ -827,8 +827,8 @@ packages:
engines: {node: '>=8.6'}
dev: true
- /postcss@8.4.37:
- resolution: {integrity: sha512-7iB/v/r7Woof0glKLH8b1SPHrsX7uhdO+Geb41QpF/+mWZHU3uxxSlN+UXGVit1PawOYDToO+AbZzhBzWRDwbQ==}
+ /postcss@8.4.38:
+ resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.3.7
@@ -944,8 +944,8 @@ packages:
picocolors: 1.0.0
sade: 1.8.1
svelte: 4.2.12
- svelte-preprocess: 5.1.3(svelte@4.2.12)(typescript@5.4.2)
- typescript: 5.4.2
+ svelte-preprocess: 5.1.3(svelte@4.2.12)(typescript@5.4.3)
+ typescript: 5.4.3
transitivePeerDependencies:
- '@babel/core'
- coffeescript
@@ -967,7 +967,7 @@ packages:
svelte: 4.2.12
dev: true
- /svelte-preprocess@5.1.3(svelte@4.2.12)(typescript@5.4.2):
+ /svelte-preprocess@5.1.3(svelte@4.2.12)(typescript@5.4.3):
resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==}
engines: {node: '>= 16.0.0', pnpm: ^8.0.0}
requiresBuild: true
@@ -1011,7 +1011,7 @@ packages:
sorcery: 0.11.0
strip-indent: 3.0.0
svelte: 4.2.12
- typescript: 5.4.2
+ typescript: 5.4.3
dev: true
/svelte@4.2.12:
@@ -1045,14 +1045,14 @@ packages:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
dev: true
- /typescript@5.4.2:
- resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==}
+ /typescript@5.4.3:
+ resolution: {integrity: sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==}
engines: {node: '>=14.17'}
hasBin: true
dev: true
- /vite@5.2.0:
- resolution: {integrity: sha512-xMSLJNEjNk/3DJRgWlPADDwaU9AgYRodDH2t6oENhJnIlmU9Hx1Q6VpjyXua/JdMw1WJRbnAgHJ9xgET9gnIAg==}
+ /vite@5.2.2:
+ resolution: {integrity: sha512-FWZbz0oSdLq5snUI0b6sULbz58iXFXdvkZfZWR/F0ZJuKTSPO7v72QPXt6KqYeMFb0yytNp6kZosxJ96Nr/wDQ==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
@@ -1080,13 +1080,13 @@ packages:
optional: true
dependencies:
esbuild: 0.20.2
- postcss: 8.4.37
+ postcss: 8.4.38
rollup: 4.13.0
optionalDependencies:
fsevents: 2.3.3
dev: true
- /vitefu@0.2.5(vite@5.2.0):
+ /vitefu@0.2.5(vite@5.2.2):
resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==}
peerDependencies:
vite: ^3.0.0 || ^4.0.0 || ^5.0.0
@@ -1094,7 +1094,7 @@ packages:
vite:
optional: true
dependencies:
- vite: 5.2.0
+ vite: 5.2.2
dev: true
/wrappy@1.0.2:
diff --git a/examples/custom-html/public/vite.svg b/examples/layouts/public/vite.svg
similarity index 100%
rename from examples/custom-html/public/vite.svg
rename to examples/layouts/public/vite.svg
diff --git a/examples/layouts/src/pages/index.svelte b/examples/layouts/src/pages/index.svelte
new file mode 100644
index 0000000..4040b66
--- /dev/null
+++ b/examples/layouts/src/pages/index.svelte
@@ -0,0 +1 @@
+content
diff --git a/examples/layouts/src/pages/layout.html b/examples/layouts/src/pages/layout.html
new file mode 100644
index 0000000..51e9424
--- /dev/null
+++ b/examples/layouts/src/pages/layout.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ Layout 1
+
+
+
+
+
+
+
diff --git a/examples/layouts/src/pages/layout2/index.svelte b/examples/layouts/src/pages/layout2/index.svelte
new file mode 100644
index 0000000..4040b66
--- /dev/null
+++ b/examples/layouts/src/pages/layout2/index.svelte
@@ -0,0 +1 @@
+content
diff --git a/examples/layouts/src/pages/layout2/layout.html b/examples/layouts/src/pages/layout2/layout.html
new file mode 100644
index 0000000..1e3be6d
--- /dev/null
+++ b/examples/layouts/src/pages/layout2/layout.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ Layout 2
+
+
+
+
+
+
+
diff --git a/examples/layouts/src/pages/layout2/sub/index.svelte b/examples/layouts/src/pages/layout2/sub/index.svelte
new file mode 100644
index 0000000..4040b66
--- /dev/null
+++ b/examples/layouts/src/pages/layout2/sub/index.svelte
@@ -0,0 +1 @@
+content
diff --git a/examples/layouts/src/pages/sub/index.svelte b/examples/layouts/src/pages/sub/index.svelte
new file mode 100644
index 0000000..4040b66
--- /dev/null
+++ b/examples/layouts/src/pages/sub/index.svelte
@@ -0,0 +1 @@
+content
diff --git a/examples/custom-html/src/vite-env.d.ts b/examples/layouts/src/vite-env.d.ts
similarity index 100%
rename from examples/custom-html/src/vite-env.d.ts
rename to examples/layouts/src/vite-env.d.ts
diff --git a/examples/custom-html/svelte.config.js b/examples/layouts/svelte.config.js
similarity index 100%
rename from examples/custom-html/svelte.config.js
rename to examples/layouts/svelte.config.js
diff --git a/examples/custom-html/tsconfig.json b/examples/layouts/tsconfig.json
similarity index 100%
rename from examples/custom-html/tsconfig.json
rename to examples/layouts/tsconfig.json
diff --git a/examples/custom-html/tsconfig.node.json b/examples/layouts/tsconfig.node.json
similarity index 100%
rename from examples/custom-html/tsconfig.node.json
rename to examples/layouts/tsconfig.node.json
diff --git a/examples/custom-html/vite.config.ts b/examples/layouts/vite.config.ts
similarity index 75%
rename from examples/custom-html/vite.config.ts
rename to examples/layouts/vite.config.ts
index 295dbe3..c795d22 100644
--- a/examples/custom-html/vite.config.ts
+++ b/examples/layouts/vite.config.ts
@@ -4,5 +4,5 @@ import { multipage } from '../../src/index'
// https://vitejs.dev/config/
export default defineConfig({
- plugins: [svelte(), multipage({ customHtml: 'custom.html' })],
+ plugins: [svelte(), multipage()],
})
diff --git a/src/boilerplate/html.ts b/src/boilerplate/html.ts
index 327c610..93c28b3 100644
--- a/src/boilerplate/html.ts
+++ b/src/boilerplate/html.ts
@@ -2,13 +2,13 @@ import { minify } from "html-minifier-terser";
import type { Config } from "../types";
import fs from "fs";
-export const html = async (body: string, config?: Config): Promise => {
+export const html = async (body: string, config?: Config, layout?: string) => {
let code = "";
- if (config?.customHtml) {
- const customHtml = fs.readFileSync(config.customHtml, "utf-8");
+ if (layout && fs.existsSync(layout)) {
+ const customHtml = fs.readFileSync(layout, "utf-8");
- code = customHtml.replace("{% body %}", body);
+ code = customHtml.replace(" ", body);
} else {
code = `
diff --git a/src/boilerplate/index.ts b/src/boilerplate/index.ts
index d8e3509..7809ce6 100644
--- a/src/boilerplate/index.ts
+++ b/src/boilerplate/index.ts
@@ -4,14 +4,14 @@ import { svelte } from "./frameworks/svelte";
import { vue } from "./frameworks/vue";
import { html } from "./html";
-export const generateBoilerplate = async (file: string, framework: string, config: Config): Promise => {
+export const generateBoilerplate = async (file: string, framework: string, config: Config, layout: string) => {
switch (framework) {
case "svelte":
- return await html(svelte(file), config);
+ return await html(svelte(file), config, layout);
case "vue":
- return await html(vue(file), config);
+ return await html(vue(file), config, layout);
case "tsx" || "jsx":
- return await html(react(file), config);
+ return await html(react(file), config, layout);
default:
return "";
};
diff --git a/src/index.ts b/src/index.ts
index eb7c10d..1b11d8e 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -83,7 +83,22 @@ export const multipage = (config?: Config): Plugin => {
const page = id.replace(fileName, `index.${framework}`);
- return await generateBoilerplate(page, framework, config || {})
+ const layouts = await glob("../**/layout.html", {
+ cwd: dirname(id),
+ filesOnly: true,
+ });
+
+ if (layouts.length < 1 || typeof layouts[0] != "string") return await generateBoilerplate(page, framework, config || {}, "");
+
+ const nearestLayout = layouts.sort((a, b) => {
+ return a.split("/").length - b.split("/").length;
+ });
+
+ if (nearestLayout.length < 1 || typeof nearestLayout[0] != "string") throw new Error("Nearest layout not found");
+
+ const layout = resolve(dirname(id), nearestLayout[0]);
+
+ return await generateBoilerplate(page, framework, config || {}, layout);
},
configureServer: createServer,
diff --git a/src/types.ts b/src/types.ts
index 30a3d19..a118640 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -5,7 +5,6 @@ export type Config = {
directory?: string;
page?: Page;
framework?: string;
- customHtml?: string;
minify?: Options;
assets?: Target[];
};