buner 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js ADDED
@@ -0,0 +1,171 @@
1
+ import { createServer as createServer$1, loadEnv } from "vite";
2
+ import fs$1 from "node:fs";
3
+ import path$1 from "node:path";
4
+ import express from "express";
5
+ import serveStatic from "serve-static";
6
+ import chalk from "chalk";
7
+ import fs from "fs";
8
+ import path from "path";
9
+ import * as cheerio from "cheerio";
10
+ import jsBeautify from "js-beautify";
11
+ const createViteDevServer = ({ root: root2, baseUrl, hmrPort, isTest: isTest2 }) => {
12
+ const server = createServer$1({
13
+ root: root2,
14
+ base: baseUrl,
15
+ logLevel: isTest2 ? "error" : "info",
16
+ server: {
17
+ middlewareMode: true,
18
+ watch: {
19
+ // During tests we edit the files too fast and sometimes chokidar
20
+ // misses change events, so enforce polling for consistency
21
+ usePolling: true,
22
+ interval: 200
23
+ },
24
+ hmr: {
25
+ port: hmrPort
26
+ }
27
+ },
28
+ appType: "custom"
29
+ });
30
+ return server;
31
+ };
32
+ const beautifyOptions = {
33
+ indent_size: 2,
34
+ indent_char: " ",
35
+ keep_array_indentation: false,
36
+ break_chained_methods: false,
37
+ indent_scripts: "normal",
38
+ brace_style: "expand",
39
+ space_before_conditional: true,
40
+ unescape_strings: false,
41
+ jslint_happy: false,
42
+ end_with_newline: false,
43
+ wrap_line_length: 0,
44
+ indent_inner_html: false,
45
+ comma_first: false,
46
+ e4x: false,
47
+ indent_empty_lines: false,
48
+ wrap_attributes: "force"
49
+ };
50
+ const updateResourcePath = ($, tagName, attr) => {
51
+ $(tagName).each((_, el) => {
52
+ const href = $(el).attr(attr);
53
+ if (href && href.startsWith("/")) {
54
+ let newPath = href;
55
+ if (process.env.VITE_DOMAIN) {
56
+ newPath = process.env.VITE_DOMAIN + newPath;
57
+ }
58
+ if (href.startsWith("/") && !href.startsWith("/assets/vendors/") && [".css", ".ico", ".js", ".webmanifest", ".svg"].includes(path.extname(href).toLowerCase()) && !/\.0x[a-z0-9]{8}\.\w+$/gi.test(href)) {
59
+ newPath += "?v=" + (/* @__PURE__ */ new Date()).getTime();
60
+ }
61
+ if (newPath != href) {
62
+ $(el).attr(attr, newPath);
63
+ }
64
+ }
65
+ });
66
+ };
67
+ const removeDuplicateAssets = ($, selector, attr, paths) => {
68
+ $(selector).each((_, el) => {
69
+ if ($(el).attr("data-pl-inplace") === "true") {
70
+ return;
71
+ }
72
+ const path2 = $(el).attr(attr);
73
+ if (!path2) {
74
+ return;
75
+ }
76
+ const index = $(el).index();
77
+ const parent = $(el).parent().clone();
78
+ const child = parent.children()[index];
79
+ parent.empty();
80
+ parent.append(child);
81
+ const html = parent.html();
82
+ $(el).after("\n<!-- " + html + " -->");
83
+ if (paths.includes(path2)) {
84
+ $(el).remove();
85
+ return;
86
+ }
87
+ paths.push(path2);
88
+ $("head").append(el);
89
+ });
90
+ };
91
+ const _useRenderer = ({ app, indexProd, isProd: isProd2, viteDevServer, resolve }) => {
92
+ app.use(async (req, res) => {
93
+ try {
94
+ let template, render;
95
+ if (!isProd2) {
96
+ template = fs.readFileSync(resolve("index.html"), "utf-8");
97
+ template = await viteDevServer.transformIndexHtml(req.originalUrl, template);
98
+ render = (await viteDevServer.ssrLoadModule(resolve("src/entry-server.tsx"))).render;
99
+ } else {
100
+ template = indexProd;
101
+ render = (await import(resolve("dist/server/entry-server.js"))).render;
102
+ }
103
+ const context = {};
104
+ const output = render(req.originalUrl);
105
+ if (context.url) {
106
+ return res.redirect(301, context.url);
107
+ }
108
+ const html = template.replace("<!--app-html-->", output.html);
109
+ const $ = cheerio.load(html);
110
+ const paths = [];
111
+ removeDuplicateAssets($, "link[data-pl-require][href]", "href", paths);
112
+ removeDuplicateAssets($, "script[data-pl-require][src]", "src", paths);
113
+ updateResourcePath($, "link", "href");
114
+ updateResourcePath($, "script", "src");
115
+ updateResourcePath($, "img", "src");
116
+ res.status(200).set({ "Content-Type": "text/html" }).end(jsBeautify.html_beautify($.html(), beautifyOptions).replace("/* app-styles */", output.styles));
117
+ } catch (e) {
118
+ !isProd2 && viteDevServer.ssrFixStacktrace(e);
119
+ console.log(e.stack);
120
+ res.status(500).end(e.stack);
121
+ }
122
+ });
123
+ };
124
+ const argvModeIndex$1 = process.argv.indexOf("--mode");
125
+ const mode$1 = argvModeIndex$1 >= 0 && argvModeIndex$1 < process.argv.length - 1 && !process.argv[argvModeIndex$1 + 1].startsWith("-") ? process.argv[argvModeIndex$1 + 1] : "production";
126
+ process.env.MY_CUSTOM_SECRET = "API_KEY_4c2928b5a14b475d94c3579cbea06178";
127
+ const isProd = process.env.NODE_ENV === "production";
128
+ const createServer = async ({ root: root2, hmrPort, baseUrl, isTest: isTest2 }) => {
129
+ const resolve = (p) => path$1.join(root2, p);
130
+ const indexProd = isProd ? fs$1.readFileSync(resolve("index.html"), "utf-8") : "";
131
+ const app = express();
132
+ let viteDevServer;
133
+ if (!isProd) {
134
+ viteDevServer = await createViteDevServer({ root: root2, baseUrl, hmrPort, isTest: isTest2 });
135
+ app.use(viteDevServer.middlewares);
136
+ }
137
+ app.use("/assets/images", serveStatic(resolve("public/assets/images"), { index: false }));
138
+ app.use("/assets/fonts", serveStatic(resolve("public/assets/fonts"), { index: false }));
139
+ app.use("/assets/css", serveStatic(resolve("public/assets/css"), { index: false }));
140
+ app.use("/assets/js", serveStatic(resolve("public/assets/js"), { index: false }));
141
+ app.use("/assets/vendors", serveStatic(resolve("public/assets/vendors"), { index: false }));
142
+ app.use("/assets", serveStatic(resolve("dist/assets"), { index: false }));
143
+ app.use("/samples", serveStatic(resolve("public/samples"), { index: false }));
144
+ _useRenderer({ app, indexProd, isProd, viteDevServer, resolve });
145
+ return { app, viteDevServer };
146
+ };
147
+ const startServer = (props) => {
148
+ createServer(props).then(({ app }) => {
149
+ app.listen(props.port, () => {
150
+ const xpackEnv2 = loadEnv(mode$1, props.root);
151
+ console.log("Running on " + chalk.green("http://localhost:" + props.port + xpackEnv2.VITE_BASE_URL));
152
+ });
153
+ });
154
+ };
155
+ console.log("[INIT] server");
156
+ const argvModeIndex = process.argv.indexOf("--mode");
157
+ const mode = argvModeIndex >= 0 && argvModeIndex < process.argv.length - 1 && !process.argv[argvModeIndex + 1].startsWith("-") ? process.argv[argvModeIndex + 1] : "production";
158
+ const root = process.cwd();
159
+ const xpackEnv = loadEnv(mode, root);
160
+ const isTest = !!xpackEnv.VITE_TEST_BUILD || process.env.NODE_ENV === "test";
161
+ const port = xpackEnv.VITE_PORT ? parseInt(xpackEnv.VITE_PORT) : 5e3;
162
+ if (!isTest) {
163
+ console.log(root);
164
+ startServer({
165
+ root,
166
+ isTest,
167
+ port,
168
+ hmrPort: port + 1,
169
+ baseUrl: xpackEnv.VITE_BASE_URL
170
+ });
171
+ }
package/dist/states.js ADDED
@@ -0,0 +1,41 @@
1
+ import fs from "fs";
2
+ import chokidar from "chokidar";
3
+ import debounce from "debounce";
4
+ import { glob } from "glob";
5
+ const isWatch = process.argv.includes("--watch");
6
+ const log = console.log.bind(console);
7
+ const states = {};
8
+ const buildStates = debounce(() => {
9
+ const output = [];
10
+ const keys = Object.keys(states);
11
+ [].forEach.call(keys, (key) => {
12
+ const state = states[key];
13
+ if (!state) {
14
+ return;
15
+ }
16
+ try {
17
+ output.push(JSON.parse(state));
18
+ } catch (error) {
19
+ console.log(error);
20
+ }
21
+ });
22
+ const json = JSON.stringify(output, null, " ");
23
+ fs.writeFileSync("public/pl-states.json", json);
24
+ }, 500);
25
+ const setStates = (statePath) => {
26
+ const state = fs.readFileSync(statePath, "utf-8");
27
+ states[statePath] = state;
28
+ buildStates();
29
+ };
30
+ const removeStates = (statePath) => {
31
+ delete states[statePath];
32
+ buildStates();
33
+ };
34
+ if (isWatch) {
35
+ const watcher = chokidar.watch("src/**/*.states.json");
36
+ watcher.on("ready", () => {
37
+ log("States are ready!");
38
+ }).on("add", (path) => setStates(path)).on("change", (path) => setStates(path)).on("unlink", (path) => removeStates(path));
39
+ } else {
40
+ glob.sync("src/**/*.states.json").forEach((path) => setStates(path));
41
+ }
package/dist/styles.js ADDED
@@ -0,0 +1,165 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { pathToFileURL, fileURLToPath } from "url";
4
+ import { watch } from "chokidar";
5
+ import * as sass from "sass";
6
+ import slash from "slash";
7
+ import debounce from "debounce";
8
+ import { glob } from "glob";
9
+ import postcss from "postcss";
10
+ import autoprefixer from "autoprefixer";
11
+ import cssnano from "cssnano";
12
+ const isWatch = process.argv.includes("--watch");
13
+ const outDir = "./public/assets/css";
14
+ if (!isWatch && fs.existsSync(outDir)) {
15
+ fs.rmSync(outDir, { force: true, recursive: true });
16
+ }
17
+ if (!fs.existsSync(outDir)) {
18
+ fs.mkdirSync(outDir, { recursive: true });
19
+ }
20
+ const log = console.log.bind(console);
21
+ const prepareCssFileContent = ({
22
+ srcFile,
23
+ includeMixins = true,
24
+ includeAbstracts = true
25
+ }) => {
26
+ return [
27
+ includeAbstracts ? slash(`@use '${path.relative(path.dirname(srcFile), path.resolve("src/assets/styles/00-abstracts/abstracts"))}' as *;
28
+ `) : void 0,
29
+ includeMixins ? slash(`@use '${path.relative(path.dirname(srcFile), path.resolve("src/assets/styles/01-mixins/mixins"))}' as *;
30
+ `) : void 0,
31
+ fs.readFileSync(srcFile, "utf-8")
32
+ ].filter(Boolean);
33
+ };
34
+ const stringOptions = (srcFile) => {
35
+ const options = {
36
+ sourceMap: true,
37
+ sourceMapIncludeSources: true,
38
+ syntax: "scss",
39
+ style: "compressed",
40
+ url: pathToFileURL(path.resolve(srcFile)),
41
+ importer: {
42
+ canonicalize(url) {
43
+ return new URL(url);
44
+ },
45
+ load(canonicalUrl) {
46
+ let filePath = fileURLToPath(canonicalUrl);
47
+ if (!filePath.endsWith(".scss")) {
48
+ const parentDir = path.dirname(filePath);
49
+ const fileName = path.basename(filePath);
50
+ filePath = path.join(parentDir, fileName + ".scss");
51
+ if (!fs.existsSync(filePath)) {
52
+ filePath = path.join(parentDir, "_" + fileName + ".scss");
53
+ }
54
+ }
55
+ if (!fs.existsSync(filePath)) return null;
56
+ if (filePath.includes("abstracts") || filePath.includes("_mixins") || filePath.includes("_base") || filePath.includes("xpack"))
57
+ return {
58
+ contents: fs.readFileSync(filePath, "utf-8"),
59
+ syntax: "scss"
60
+ };
61
+ let content = prepareCssFileContent({ srcFile: filePath });
62
+ if (filePath.includes("mixins")) {
63
+ content = prepareCssFileContent({ srcFile: filePath, includeMixins: false });
64
+ }
65
+ return {
66
+ contents: content.join(""),
67
+ syntax: "scss"
68
+ };
69
+ }
70
+ }
71
+ };
72
+ return options;
73
+ };
74
+ const compile = (srcFile, options) => {
75
+ if (options.isReady) {
76
+ log("compile:", slash(srcFile));
77
+ }
78
+ if (path.basename(srcFile).startsWith("_")) {
79
+ return;
80
+ }
81
+ const name = path.basename(srcFile) === "index.scss" ? path.basename(path.dirname(srcFile)) + ".css" : path.basename(srcFile).replace(/\.scss$/gi, ".css");
82
+ const outFile = (options.prefix ?? "") + name;
83
+ const cssStrings = srcFile.includes("xpack") ? [fs.readFileSync(srcFile, "utf-8")] : prepareCssFileContent({ srcFile });
84
+ if (srcFile.includes("style-base") || srcFile.includes("style-all")) {
85
+ glob.sync("./src/atoms/**/*.scss").forEach((atomPath) => {
86
+ if (!path.basename(atomPath).startsWith("_")) {
87
+ cssStrings.push(sass.compileString(prepareCssFileContent({ srcFile: atomPath }).join(""), stringOptions(atomPath)).css);
88
+ }
89
+ });
90
+ glob.sync("./src/molecules/**/*.scss").forEach((molPath) => {
91
+ if (!path.basename(molPath).startsWith("_")) {
92
+ cssStrings.push(sass.compileString(prepareCssFileContent({ srcFile: molPath }).join(""), stringOptions(molPath)).css);
93
+ }
94
+ });
95
+ }
96
+ sass.compileStringAsync(cssStrings.join(""), stringOptions(srcFile)).then((result) => postcssProcess(result, srcFile, outFile)).catch((error) => {
97
+ log(error);
98
+ });
99
+ };
100
+ const postcssProcess = (result, from, to) => {
101
+ const postcssOptions = { from: pathToFileURL(from).href, to, map: { prev: result.sourceMap, absolute: false } };
102
+ postcss([autoprefixer({ grid: true }), cssnano]).process(result.css, postcssOptions).then((result2) => {
103
+ fs.writeFileSync(path.join(outDir, to), result2.css + (result2.map ? `
104
+ /*# sourceMappingURL=${to}.map */` : ""));
105
+ if (result2.map) {
106
+ fs.writeFileSync(path.join(outDir, to + ".map"), result2.map.toString());
107
+ }
108
+ });
109
+ };
110
+ const styleOrganisms = debounce((isReady) => {
111
+ const paths = glob.sync("src/organisms/**/*.scss", { nodir: true });
112
+ [].forEach.call(paths, (p) => styleOrganism(p, isReady));
113
+ }, 200);
114
+ const styleTemplates = debounce((isReady) => {
115
+ const paths = glob.sync("src/templates/**/*.scss", { nodir: true });
116
+ [].forEach.call(paths, (p) => styleTemplate(p, isReady));
117
+ }, 200);
118
+ const styleBase = debounce((isReady) => compile("src/assets/styles/style-base.scss", { isReady }), 200);
119
+ const stylePlState = debounce((isReady) => compile("xpack/styles/pl-states.scss", { isReady }), 200);
120
+ const styleRoot = debounce((isReady) => compile("xpack/styles/root.scss", { isReady }), 200);
121
+ const styleOrganism = (srcFile, isReady) => compile(srcFile, { prefix: "b-", isReady });
122
+ const styleTemplate = (srcFile, isReady) => compile(srcFile, { prefix: "p-", isReady });
123
+ const sassCompile = (inputPath, isReady) => {
124
+ const p = slash(inputPath);
125
+ if (p.startsWith("src/assets/styles/00-abstracts/") || p.startsWith("src/assets/styles/01-mixins/")) {
126
+ styleBase(isReady);
127
+ styleOrganisms(isReady);
128
+ styleTemplates(isReady);
129
+ stylePlState(isReady);
130
+ }
131
+ if (p.startsWith("src/atoms") || p.startsWith("src/molecules") || p.startsWith("src/assets/styles/02-base")) {
132
+ styleBase(isReady);
133
+ }
134
+ if (p.startsWith("src/organisms")) {
135
+ if (path.basename(p).startsWith("_")) {
136
+ glob.sync(path.dirname(p) + "/*.scss", { nodir: true }).filter((p2) => !path.basename(p2).startsWith("_")).forEach((p2) => styleOrganism(p2, isReady));
137
+ } else {
138
+ styleOrganism(p, isReady);
139
+ }
140
+ }
141
+ if (p.startsWith("src/templates")) {
142
+ if (path.basename(p).startsWith("_")) {
143
+ glob.sync(path.dirname(p) + "/*.scss", { nodir: true }).filter((p2) => !path.basename(p2).startsWith("_")).forEach((p2) => styleTemplate(p2, isReady));
144
+ } else {
145
+ styleTemplate(p, isReady);
146
+ }
147
+ }
148
+ if (p.startsWith("xpack/styles/pl-states")) {
149
+ stylePlState(isReady);
150
+ } else if (p.startsWith("xpack/styles")) {
151
+ styleRoot(isReady);
152
+ }
153
+ };
154
+ if (isWatch) {
155
+ const watcher = watch(["src", "xpack/styles"], { ignored: (path2, stats) => !!stats?.isFile() && !path2.endsWith(".scss") });
156
+ let isReady = false;
157
+ watcher.on("ready", () => {
158
+ log("SCSS ready!");
159
+ isReady = true;
160
+ }).on("add", (path2) => sassCompile(path2, isReady)).on("change", (path2) => sassCompile(path2, isReady)).on("unlink", (path2) => log(`File ${path2} has been removed`));
161
+ } else {
162
+ styleBase(true);
163
+ stylePlState(true);
164
+ glob.sync(["src/{organisms,templates}/**/*.scss", "xpack/styles/**/*.scss"]).filter((p) => !path.basename(p).startsWith("_")).forEach((path2) => sassCompile(path2, true));
165
+ }
package/index.html CHANGED
@@ -38,7 +38,7 @@
38
38
 
39
39
  <body>
40
40
  <!--app-html-->
41
- <script type="module" src="/xpack/react-loader-init.tsx"></script>
41
+ <script type="module" src="@xpack/react-loader-init.tsx"></script>
42
42
  <script type="module" defer src="#__BASE_URL__/assets/js/pl-states.js"></script>
43
43
  </body>
44
44
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "buner",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Frontend build toolkit for Vite + React SSR projects — SCSS pipeline, prerender, SSR dev server, and backend integration.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,20 +20,12 @@
20
20
  "cli"
21
21
  ],
22
22
  "bin": {
23
- "buner": "./bin/buner.js"
23
+ "buner": "./dist/buner.js"
24
24
  },
25
25
  "files": [
26
- "bin",
27
- "cli",
26
+ "dist",
28
27
  "xpack",
29
28
  "public",
30
- "server.ts",
31
- "prerender.ts",
32
- "integration.ts",
33
- "styles.ts",
34
- "scripts.ts",
35
- "states.ts",
36
- "migrate-scss.ts",
37
29
  "vite.config.ts",
38
30
  "index.html",
39
31
  "tsconfig.json",
@@ -91,7 +83,6 @@
91
83
  "prompts": "^2.4.2",
92
84
  "sass": "^1.89.2",
93
85
  "slash": "^5.1.0",
94
- "tsx": "^4.19.0",
95
86
  "validate-npm-package-name": "^7.0.0",
96
87
  "vite": "^7.0.6"
97
88
  },
package/xpack/alias.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import path from 'path';
2
2
 
3
- import { root, srcRoot } from './paths';
3
+ import { root, srcRoot, packageRoot } from './paths';
4
4
 
5
5
  const alias = [
6
+ { find: '@src', replacement: srcRoot },
6
7
  { find: '@atoms', replacement: path.resolve(srcRoot, 'atoms') },
7
8
  { find: '@molecules', replacement: path.resolve(srcRoot, 'molecules') },
8
9
  { find: '@organisms', replacement: path.resolve(srcRoot, 'organisms') },
@@ -15,7 +16,7 @@ const alias = [
15
16
  { find: '@_http', replacement: path.resolve(srcRoot, '_http') },
16
17
  { find: '@_api', replacement: path.resolve(srcRoot, '_api') },
17
18
  { find: '@mocks', replacement: path.resolve(srcRoot, 'mocks') },
18
- { find: '@xpack', replacement: path.resolve(root, 'xpack') },
19
+ { find: '@xpack', replacement: path.resolve(packageRoot, 'xpack') },
19
20
  ];
20
21
 
21
22
  export default alias;
@@ -3,7 +3,7 @@ import path from 'path';
3
3
  import { glob } from 'glob';
4
4
  import { PluginOption } from 'vite';
5
5
 
6
- import { root, mode } from '../paths';
6
+ import { root, packageRoot, mode } from '../paths';
7
7
  const scriptOnly = process.env.scriptOnly;
8
8
 
9
9
  const options = (): PluginOption => {
@@ -16,7 +16,7 @@ const options = (): PluginOption => {
16
16
  inputs['index'] = `${root}/index.html`;
17
17
  }
18
18
 
19
- const filePaths = glob.sync(['/src/assets/**/*.entry.ts', '/xpack/scripts/**/*.entry.ts'], { root: root });
19
+ const filePaths = glob.sync([`${root}/src/assets/**/*.entry.ts`, `${packageRoot}/xpack/scripts/**/*.entry.ts`]);
20
20
 
21
21
  [].forEach.call(filePaths, (filePath: string) => {
22
22
  const fileName = path.basename(filePath).toLowerCase();
@@ -1,16 +1,18 @@
1
1
  import { PluginOption } from 'vite';
2
2
 
3
+ import { packageRoot } from '../paths';
4
+
3
5
  const transformIndexHtml = (baseUrl: string): PluginOption => {
4
6
  // console.log('[INIT] transformIndexHtml');
5
7
 
6
8
  return {
7
9
  name: 'xpack-transform-index-html',
8
- enforce: 'post',
10
+ enforce: 'pre',
9
11
 
10
12
  transformIndexHtml(html) {
11
13
  // console.log('transformIndexHtml');
12
14
 
13
- return html.replaceAll('#__BASE_URL__/', baseUrl);
15
+ return html.replaceAll('#__BASE_URL__/', baseUrl).replaceAll('@xpack/', `${packageRoot}/xpack/`);
14
16
  },
15
17
  };
16
18
  };
@@ -1,4 +1,4 @@
1
- import { blocks } from '../src/react-loader';
1
+ import { blocks } from '@src/react-loader';
2
2
  import { initReactLoader } from './react-loader';
3
3
 
4
4
  initReactLoader(blocks);
package/cli/README.md DELETED
@@ -1 +0,0 @@
1
- [![Build Status](https://episerver-es-emea.visualstudio.com/Alloy-Template/_apis/build/status%2FFE%20-%20Integration?branchName=fe-release)](https://episerver-es-emea.visualstudio.com/Alloy-Template/_build/latest?definitionId=28&branchName=fe-release)