buner 1.0.4 → 1.0.6
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/{bin → dist}/buner.js +54 -35
- package/{integration.ts → dist/integration.js} +51 -100
- package/dist/migrate-scss.js +33 -0
- package/dist/prerender.js +158 -0
- package/dist/scripts.js +36 -0
- package/dist/server.js +171 -0
- package/dist/states.js +41 -0
- package/dist/styles.js +165 -0
- package/package.json +3 -11
- package/cli/README.md +0 -1
- package/cli/buner.ts +0 -241
- package/cli/cli.ts +0 -125
- package/cli/create-app.ts +0 -59
- package/cli/helpers/copy.ts +0 -61
- package/cli/helpers/format-files.ts +0 -197
- package/cli/helpers/git.ts +0 -77
- package/cli/helpers/install.ts +0 -26
- package/cli/helpers/is-folder-empty.ts +0 -40
- package/cli/helpers/is-writeable.ts +0 -14
- package/cli/helpers/make-dir.ts +0 -7
- package/cli/helpers/validate-pkg.ts +0 -17
- package/cli/install-template.ts +0 -72
- package/migrate-scss.ts +0 -42
- package/prerender.ts +0 -229
- package/scripts.ts +0 -56
- package/server.ts +0 -29
- package/states.ts +0 -63
- package/styles.ts +0 -232
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "buner",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
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": "./
|
|
23
|
+
"buner": "./dist/buner.js"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
|
-
"
|
|
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",
|
package/cli/README.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[](https://episerver-es-emea.visualstudio.com/Alloy-Template/_build/latest?definitionId=28&branchName=fe-release)
|
package/cli/buner.ts
DELETED
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { execSync, spawn, SpawnOptions } from 'child_process';
|
|
5
|
-
import { fileURLToPath } from 'url';
|
|
6
|
-
|
|
7
|
-
import { Command } from 'commander';
|
|
8
|
-
import chalk from 'chalk';
|
|
9
|
-
import fetch from 'node-fetch';
|
|
10
|
-
import prompts from 'prompts';
|
|
11
|
-
|
|
12
|
-
import packageJson from '../package.json';
|
|
13
|
-
|
|
14
|
-
import { createApp } from './create-app.js';
|
|
15
|
-
import { validateNpmName } from './helpers/validate-pkg.js';
|
|
16
|
-
|
|
17
|
-
const { green, yellow, bold, cyan, red } = chalk;
|
|
18
|
-
const packageName = 'buner';
|
|
19
|
-
|
|
20
|
-
// Package's own directory (where server.ts, styles.ts, etc. live)
|
|
21
|
-
const packageDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
22
|
-
|
|
23
|
-
/** Resolve a file path relative to the buner package directory */
|
|
24
|
-
const pkg = (file: string) => path.join(packageDir, file);
|
|
25
|
-
|
|
26
|
-
const run = (cmd: string, args: string[] = [], options: SpawnOptions = {}) => {
|
|
27
|
-
return new Promise<void>((resolve, reject) => {
|
|
28
|
-
const child = spawn(cmd, args, {
|
|
29
|
-
stdio: 'inherit',
|
|
30
|
-
shell: true,
|
|
31
|
-
cwd: process.cwd(),
|
|
32
|
-
...options,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
child.on('close', (code) => {
|
|
36
|
-
if (code !== 0) {
|
|
37
|
-
reject(new Error(`Command "${cmd} ${args.join(' ')}" exited with code ${code}`));
|
|
38
|
-
} else {
|
|
39
|
-
resolve();
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
child.on('error', reject);
|
|
44
|
-
});
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const runSync = (cmd: string) => {
|
|
48
|
-
execSync(cmd, { stdio: 'inherit', cwd: process.cwd() });
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const onPromptState = (state: { value?: string; aborted?: boolean }) => {
|
|
52
|
-
if (state?.aborted) {
|
|
53
|
-
process.stdout.write('\x1B[?25h');
|
|
54
|
-
process.stdout.write('\n');
|
|
55
|
-
process.exit(1);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const parseVersion = (version: string): number => {
|
|
60
|
-
return parseInt(version.replaceAll('.', ''));
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const update = fetch(`https://registry.npmjs.org/${packageJson.name}/latest`)
|
|
64
|
-
.then((res) => res.json())
|
|
65
|
-
.catch(() => null);
|
|
66
|
-
|
|
67
|
-
async function notifyUpdate(): Promise<void> {
|
|
68
|
-
try {
|
|
69
|
-
const data = (await update) as { version: string };
|
|
70
|
-
|
|
71
|
-
if (data.version && parseVersion(data.version) !== parseVersion(packageJson.version)) {
|
|
72
|
-
const updateMessage = `npm update -g ${packageName}`;
|
|
73
|
-
|
|
74
|
-
console.log(
|
|
75
|
-
yellow(bold(`A new version of '${packageName}' is available!`)) + '\n' + 'You can update by running: ' + cyan(updateMessage) + '\n'
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
} catch {
|
|
79
|
-
// ignore error
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const program = new Command();
|
|
84
|
-
|
|
85
|
-
program.name(packageName).description('Frontend build toolkit for Vite + React SSR projects').version(packageJson.version);
|
|
86
|
-
|
|
87
|
-
// buner create [dir]
|
|
88
|
-
program
|
|
89
|
-
.command('create')
|
|
90
|
-
.argument('[project-directory]', 'the project name', '')
|
|
91
|
-
.description('Scaffold a new frontend project')
|
|
92
|
-
.action(async (projectPath: string) => {
|
|
93
|
-
if (!projectPath) {
|
|
94
|
-
const validation = validateNpmName('my-app');
|
|
95
|
-
|
|
96
|
-
const res = await prompts({
|
|
97
|
-
onState: onPromptState,
|
|
98
|
-
type: 'text',
|
|
99
|
-
name: 'path',
|
|
100
|
-
message: 'What is your project named?',
|
|
101
|
-
initial: 'my-app',
|
|
102
|
-
validate: (name) => {
|
|
103
|
-
const validation = validateNpmName(path.basename(path.resolve(name)));
|
|
104
|
-
|
|
105
|
-
if (validation.valid) {
|
|
106
|
-
return true;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return `Invalid project name ${validation?.problems?.[0] ? validation?.problems?.[0] : ''}`;
|
|
110
|
-
},
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
if (typeof res.path === 'string') {
|
|
114
|
-
projectPath = res.path.trim();
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (!projectPath) {
|
|
119
|
-
console.log(
|
|
120
|
-
'\nPlease specify the project directory:\n' +
|
|
121
|
-
` ${cyan('buner create')} ${green('<project-directory>')}\n` +
|
|
122
|
-
'For example:\n' +
|
|
123
|
-
` ${cyan('buner create')} ${green('my-app')}\n`
|
|
124
|
-
);
|
|
125
|
-
process.exit(1);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const resolvedProjectPath = path.resolve(projectPath);
|
|
129
|
-
|
|
130
|
-
await createApp({ appPath: resolvedProjectPath });
|
|
131
|
-
await notifyUpdate();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// buner dev
|
|
135
|
-
program
|
|
136
|
-
.command('dev')
|
|
137
|
-
.description('Start development mode with all watchers')
|
|
138
|
-
.action(async () => {
|
|
139
|
-
await run('npx', [
|
|
140
|
-
'concurrently',
|
|
141
|
-
'--kill-others',
|
|
142
|
-
`"bun ${pkg('styles.ts')} --watch"`,
|
|
143
|
-
`"bun ${pkg('states.ts')} --watch"`,
|
|
144
|
-
`"cross-env scriptOnly=true npx vite build --config ${pkg('vite.config.ts')} --mode development --watch"`,
|
|
145
|
-
`"bun ${pkg('server.ts')} --mode development"`,
|
|
146
|
-
]);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// buner serve
|
|
150
|
-
program
|
|
151
|
-
.command('serve')
|
|
152
|
-
.description('Start the SSR dev server')
|
|
153
|
-
.option('--mode <mode>', 'server mode', 'development')
|
|
154
|
-
.action(async (opts) => {
|
|
155
|
-
await run('bun', [pkg('server.ts'), '--mode', opts.mode]);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// buner build
|
|
159
|
-
program
|
|
160
|
-
.command('build')
|
|
161
|
-
.description('Build the project (static + SSR)')
|
|
162
|
-
.action(async () => {
|
|
163
|
-
runSync(`npx vite build --config ${pkg('vite.config.ts')} --outDir dist/static`);
|
|
164
|
-
runSync(`npx vite build --config ${pkg('vite.config.ts')} --ssr src/entry-server.tsx --outDir dist/server`);
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
// buner generate
|
|
168
|
-
program
|
|
169
|
-
.command('generate')
|
|
170
|
-
.description('Full static site generation (states + styles + build + prerender)')
|
|
171
|
-
.option('--mode <mode>', 'build mode', 'production')
|
|
172
|
-
.action(async (opts) => {
|
|
173
|
-
runSync(`bun ${pkg('states.ts')}`);
|
|
174
|
-
runSync(`bun ${pkg('styles.ts')}`);
|
|
175
|
-
if (opts.mode === 'production') {
|
|
176
|
-
runSync(`npx vite build --config ${pkg('vite.config.ts')} --outDir dist/static`);
|
|
177
|
-
runSync(`npx vite build --config ${pkg('vite.config.ts')} --ssr src/entry-server.tsx --outDir dist/server`);
|
|
178
|
-
} else {
|
|
179
|
-
runSync(`npx vite build --config ${pkg('vite.config.ts')} --outDir dist/static --mode ${opts.mode}`);
|
|
180
|
-
runSync(`npx vite build --config ${pkg('vite.config.ts')} --ssr src/entry-server.tsx --outDir dist/server --mode ${opts.mode}`);
|
|
181
|
-
}
|
|
182
|
-
runSync(`bun ${pkg('prerender.ts')} --add-hash --mode ${opts.mode}`);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
// buner eshn
|
|
186
|
-
program
|
|
187
|
-
.command('eshn')
|
|
188
|
-
.description('Generate with --mode eshn')
|
|
189
|
-
.action(async () => {
|
|
190
|
-
runSync(`bun ${pkg('states.ts')}`);
|
|
191
|
-
runSync(`bun ${pkg('styles.ts')}`);
|
|
192
|
-
runSync(`npx vite build --config ${pkg('vite.config.ts')} --outDir dist/static --mode eshn`);
|
|
193
|
-
runSync(`npx vite build --config ${pkg('vite.config.ts')} --ssr src/entry-server.tsx --outDir dist/server --mode eshn`);
|
|
194
|
-
runSync(`bun ${pkg('prerender.ts')} --add-hash --mode eshn`);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
// buner inte
|
|
198
|
-
program
|
|
199
|
-
.command('inte')
|
|
200
|
-
.description('Build and integrate with backend (styles + build + prerender + integration)')
|
|
201
|
-
.action(async () => {
|
|
202
|
-
runSync(`bun ${pkg('styles.ts')}`);
|
|
203
|
-
runSync(`npx vite build --config ${pkg('vite.config.ts')} --outDir dist/static`);
|
|
204
|
-
runSync(`npx vite build --config ${pkg('vite.config.ts')} --ssr src/entry-server.tsx --outDir dist/server`);
|
|
205
|
-
runSync(`bun ${pkg('prerender.ts')}`);
|
|
206
|
-
runSync(`bun ${pkg('integration.ts')}`);
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// buner styles
|
|
210
|
-
program
|
|
211
|
-
.command('styles')
|
|
212
|
-
.description('Compile SCSS')
|
|
213
|
-
.option('--watch', 'Watch for changes')
|
|
214
|
-
.action(async (opts) => {
|
|
215
|
-
const args = [pkg('styles.ts')];
|
|
216
|
-
|
|
217
|
-
if (opts.watch) args.push('--watch');
|
|
218
|
-
await run('bun', args);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// buner prerender
|
|
222
|
-
program
|
|
223
|
-
.command('prerender')
|
|
224
|
-
.description('Pre-render HTML files')
|
|
225
|
-
.option('--add-hash', 'Add content hashes to asset URLs')
|
|
226
|
-
.option('--mode <mode>', 'build mode', 'production')
|
|
227
|
-
.action(async (opts) => {
|
|
228
|
-
const args = [pkg('prerender.ts')];
|
|
229
|
-
|
|
230
|
-
if (opts.addHash) args.push('--add-hash');
|
|
231
|
-
args.push('--mode', opts.mode);
|
|
232
|
-
await run('bun', args);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
program.parseAsync(process.argv).catch(async (error) => {
|
|
236
|
-
console.log(red(error));
|
|
237
|
-
await notifyUpdate();
|
|
238
|
-
process.exit(1);
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
export { packageName };
|