@spicemod/creator 0.0.25 → 0.0.27
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/bin.mjs +169 -119
- package/dist/templates/custom-app/shared/spice.config.js +6 -0
- package/dist/templates/custom-app/shared/spice.config.ts +6 -0
- package/dist/templates/custom-app/shared/tsconfig.app.json +33 -0
- package/dist/templates/custom-app/shared/tsconfig.node.json +25 -0
- package/dist/templates/custom-app/ts/react/src/extension/index.tsx +1 -1
- package/dist/templates/extension/js/react/src/app.jsx +1 -1
- package/dist/templates/extension/shared/spice.config.js +6 -0
- package/dist/templates/extension/shared/spice.config.ts +6 -0
- package/dist/templates/extension/shared/tsconfig.app.json +33 -0
- package/dist/templates/extension/shared/tsconfig.node.json +25 -0
- package/dist/templates/extension/ts/react/src/app.tsx +1 -1
- package/dist/templates/hmrCustomApp.js +284 -0
- package/dist/templates/liveReload.js +298 -45
- package/dist/templates/theme/js/react/src/app.jsx +1 -1
- package/dist/templates/theme/shared/spice.config.js +6 -0
- package/dist/templates/theme/shared/spice.config.ts +6 -0
- package/dist/templates/theme/shared/tsconfig.app.json +33 -0
- package/dist/templates/theme/shared/tsconfig.node.json +25 -0
- package/dist/templates/theme/ts/react/src/app.tsx +1 -1
- package/package.json +1 -1
- package/templates/custom-app/shared/spice.config.js +6 -0
- package/templates/custom-app/shared/spice.config.ts +6 -0
- package/templates/custom-app/shared/tsconfig.app.json +33 -0
- package/templates/custom-app/shared/tsconfig.node.json +25 -0
- package/templates/custom-app/ts/react/src/extension/index.tsx +1 -1
- package/templates/extension/js/react/src/app.jsx +1 -1
- package/templates/extension/shared/spice.config.js +6 -0
- package/templates/extension/shared/spice.config.ts +6 -0
- package/templates/extension/shared/tsconfig.app.json +33 -0
- package/templates/extension/shared/tsconfig.node.json +25 -0
- package/templates/extension/ts/react/src/app.tsx +1 -1
- package/templates/hmrCustomApp.js +284 -0
- package/templates/liveReload.js +298 -45
- package/templates/theme/js/react/src/app.jsx +1 -1
- package/templates/theme/shared/spice.config.js +6 -0
- package/templates/theme/shared/spice.config.ts +6 -0
- package/templates/theme/shared/tsconfig.app.json +33 -0
- package/templates/theme/shared/tsconfig.node.json +25 -0
- package/templates/theme/ts/react/src/app.tsx +1 -1
package/dist/bin.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { Command, Option } from "commander";
|
|
|
3
3
|
import * as v from "valibot";
|
|
4
4
|
import path, { basename, dirname, extname, join, relative, resolve } from "node:path";
|
|
5
5
|
import { build, context, transform } from "esbuild";
|
|
6
|
-
import { createReadStream, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
6
|
+
import fs, { createReadStream, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { watchConfig } from "c12";
|
|
8
8
|
import { globSync } from "tinyglobby";
|
|
9
9
|
import { URL as URL$1, fileURLToPath } from "node:url";
|
|
@@ -13,7 +13,7 @@ import * as p from "@clack/prompts";
|
|
|
13
13
|
import { cancel, log, spinner } from "@clack/prompts";
|
|
14
14
|
import pc from "picocolors";
|
|
15
15
|
import "dotenv/config";
|
|
16
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
16
|
+
import { readFile, unlink, writeFile } from "node:fs/promises";
|
|
17
17
|
import { parse } from "ini";
|
|
18
18
|
import { gzipSync } from "node:zlib";
|
|
19
19
|
import postcssMinify from "@csstools/postcss-minify";
|
|
@@ -137,13 +137,14 @@ const frameworks = frameworkTypes.map((name) => ({
|
|
|
137
137
|
}));
|
|
138
138
|
const frameworkOptions = toOptions(frameworks);
|
|
139
139
|
const liveReloadFilePath = dist(`templates/liveReload.js`, import.meta.url);
|
|
140
|
+
const hmrCustomAppFilePath = dist(`templates/hmrCustomApp.js`, import.meta.url);
|
|
140
141
|
const templateWrapperFilePath = dist("templates/wrapper.js", import.meta.url);
|
|
141
142
|
const customAppEntryFilePath = dist("templates/customAppEntry.js", import.meta.url);
|
|
142
143
|
|
|
143
144
|
//#endregion
|
|
144
145
|
//#region package.json
|
|
145
146
|
var name = "@spicemod/creator";
|
|
146
|
-
var version = "0.0.
|
|
147
|
+
var version = "0.0.27";
|
|
147
148
|
|
|
148
149
|
//#endregion
|
|
149
150
|
//#region src/utils/common.ts
|
|
@@ -779,15 +780,48 @@ function getTime(start) {
|
|
|
779
780
|
}
|
|
780
781
|
|
|
781
782
|
//#endregion
|
|
782
|
-
//#region src/esbuild/plugins/
|
|
783
|
-
|
|
784
|
-
|
|
783
|
+
//#region src/esbuild/plugins/buildErrorReporter.ts
|
|
784
|
+
function buildErrorReporter({ server }) {
|
|
785
|
+
return {
|
|
786
|
+
name: "spice_internal__build-error-reporter",
|
|
787
|
+
setup(build) {
|
|
788
|
+
build.onEnd(async (result) => {
|
|
789
|
+
const errors = result.errors;
|
|
790
|
+
const warnings = result.warnings;
|
|
791
|
+
if (errors.length === 0) {
|
|
792
|
+
server?.broadcast({
|
|
793
|
+
type: "build-success",
|
|
794
|
+
errors: [],
|
|
795
|
+
warnings
|
|
796
|
+
});
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
server?.broadcast({
|
|
800
|
+
type: "build-error",
|
|
801
|
+
errors,
|
|
802
|
+
warnings
|
|
803
|
+
});
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
//#endregion
|
|
810
|
+
//#region src/esbuild/plugins/clean.ts
|
|
811
|
+
const clean = (cache, logger = createLogger("plugin:clean")) => ({
|
|
812
|
+
name: "clean",
|
|
785
813
|
setup(build) {
|
|
814
|
+
const outdir = resolve(build.initialOptions.outdir || "./dist");
|
|
786
815
|
build.onStart(() => {
|
|
787
|
-
if (existsSync(
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
816
|
+
if (fs.existsSync(outdir)) try {
|
|
817
|
+
fs.rmSync(outdir, {
|
|
818
|
+
recursive: true,
|
|
819
|
+
force: true
|
|
820
|
+
});
|
|
821
|
+
logger.log(`Removed: ${outdir}`);
|
|
822
|
+
} catch (err) {
|
|
823
|
+
logger.error(`Error removing ${outdir}:`, err);
|
|
824
|
+
}
|
|
791
825
|
});
|
|
792
826
|
}
|
|
793
827
|
});
|
|
@@ -847,6 +881,37 @@ const externalGlobal = (externals, namespace = "spicetify-global") => {
|
|
|
847
881
|
|
|
848
882
|
//#endregion
|
|
849
883
|
//#region src/esbuild/plugins/spicetifyHandlers.ts
|
|
884
|
+
async function removeFile(logger, targetPath) {
|
|
885
|
+
try {
|
|
886
|
+
await unlink(targetPath);
|
|
887
|
+
logger.debug(pc.green(`${CHECK} Removed: ${targetPath}`));
|
|
888
|
+
} catch (err) {
|
|
889
|
+
if (err.code !== "ENOENT") logger.error(pc.red(`${CROSS} Failed to remove file: ${err instanceof Error ? err.message : String(err)}`));
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
async function copyFiles(logger, destDirs, cacheFiles) {
|
|
893
|
+
const tasks = [];
|
|
894
|
+
for (const filePath of cacheFiles.keys()) {
|
|
895
|
+
const fileData = cacheFiles.get(filePath);
|
|
896
|
+
if (!fileData) continue;
|
|
897
|
+
for (const destDir of destDirs) {
|
|
898
|
+
const targetPath = resolve(destDir, basename(filePath));
|
|
899
|
+
tasks.push((async () => {
|
|
900
|
+
await mkdirp(destDir);
|
|
901
|
+
await writeFile(targetPath, fileData.contents);
|
|
902
|
+
})());
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
await Promise.all(tasks);
|
|
906
|
+
}
|
|
907
|
+
async function removeDeletedFiles(logger, destDirs, removedFiles) {
|
|
908
|
+
const tasks = [];
|
|
909
|
+
for (const removedPath of removedFiles) for (const destDir of destDirs) {
|
|
910
|
+
const targetPath = resolve(destDir, basename(removedPath));
|
|
911
|
+
tasks.push(removeFile(logger, targetPath));
|
|
912
|
+
}
|
|
913
|
+
await Promise.all(tasks);
|
|
914
|
+
}
|
|
850
915
|
const spicetifyHandler = ({ config, options, cache, logger = createLogger("plugin:spicetify-handler") }) => ({
|
|
851
916
|
name: "spice_internal__spicetify-build-handler",
|
|
852
917
|
async setup(build) {
|
|
@@ -855,27 +920,23 @@ const spicetifyHandler = ({ config, options, cache, logger = createLogger("plugi
|
|
|
855
920
|
const isExtension = config.template === "extension";
|
|
856
921
|
const isCustomApp = config.template === "custom-app";
|
|
857
922
|
const identifier = isExtension ? `${urlSlugify(config.name)}.js` : urlSlugify(getEnName(config.name));
|
|
923
|
+
const getDestDirs = () => {
|
|
924
|
+
const dirs = [resolve(outDir)];
|
|
925
|
+
if (copy) dirs.push(isExtension ? getExtensionDir() : isCustomApp ? resolve(getCustomAppsDir(), identifier) : resolve(getThemesDir(), identifier));
|
|
926
|
+
return dirs;
|
|
927
|
+
};
|
|
858
928
|
if (env.skipSpicetify) {
|
|
859
929
|
logger.info(pc.yellow("skipping spicetify operations"));
|
|
860
930
|
build.onEnd(async (result) => {
|
|
861
931
|
if (result.errors.length > 0) return;
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
tasks.push((async () => {
|
|
869
|
-
await mkdirp(outDir);
|
|
870
|
-
await writeFile(targetPath, fileData.contents);
|
|
871
|
-
})());
|
|
872
|
-
}
|
|
873
|
-
try {
|
|
874
|
-
await Promise.all(tasks);
|
|
875
|
-
logger.debug(pc.green(`${CHECK} Built files written to ${outDir}`));
|
|
876
|
-
} catch (err) {
|
|
877
|
-
logger.error(pc.red(`${CROSS} Failed to write files: ${err instanceof Error ? err.message : String(err)}`));
|
|
932
|
+
const destDirs = getDestDirs();
|
|
933
|
+
await copyFiles(logger, destDirs, cache.files);
|
|
934
|
+
logger.debug(pc.green(`${CHECK} Built files written to ${outDir}`));
|
|
935
|
+
if (cache.removed.size > 0) {
|
|
936
|
+
await removeDeletedFiles(logger, destDirs, cache.removed);
|
|
937
|
+
cache.hasChanges = true;
|
|
878
938
|
}
|
|
939
|
+
cache.removed.clear();
|
|
879
940
|
});
|
|
880
941
|
return;
|
|
881
942
|
}
|
|
@@ -909,28 +970,19 @@ const spicetifyHandler = ({ config, options, cache, logger = createLogger("plugi
|
|
|
909
970
|
}
|
|
910
971
|
build.onEnd(async (result) => {
|
|
911
972
|
if (result.errors.length > 0) return;
|
|
912
|
-
|
|
913
|
-
const destDirs = [resolve(outDir)];
|
|
914
|
-
if (copy) destDirs.push(isExtension ? getExtensionDir() : isCustomApp ? resolve(getCustomAppsDir(), identifier) : resolve(getThemesDir(), identifier));
|
|
915
|
-
const tasks = [];
|
|
916
|
-
for (const filePath of cache.changed) {
|
|
917
|
-
const fileData = cache.files.get(filePath);
|
|
918
|
-
if (!fileData) continue;
|
|
919
|
-
for (const destDir of destDirs) {
|
|
920
|
-
const targetPath = resolve(destDir, basename(filePath));
|
|
921
|
-
tasks.push((async () => {
|
|
922
|
-
await mkdirp(destDir);
|
|
923
|
-
await writeFile(targetPath, fileData.contents);
|
|
924
|
-
})());
|
|
925
|
-
}
|
|
926
|
-
}
|
|
973
|
+
const destDirs = getDestDirs();
|
|
927
974
|
try {
|
|
928
|
-
await
|
|
975
|
+
await copyFiles(logger, destDirs, cache.files);
|
|
929
976
|
logger.debug(pc.green(`${CHECK} Changed files copied.`));
|
|
930
977
|
} catch (err) {
|
|
931
978
|
logger.error(pc.red(`${CROSS} Failed to copy files: ${err instanceof Error ? err.message : String(err)}`));
|
|
932
979
|
return;
|
|
933
980
|
}
|
|
981
|
+
if (cache.removed.size > 0) {
|
|
982
|
+
await removeDeletedFiles(logger, destDirs, cache.removed);
|
|
983
|
+
cache.hasChanges = true;
|
|
984
|
+
}
|
|
985
|
+
cache.removed.clear();
|
|
934
986
|
if (apply && cache.hasChanges && (!applyOnce || !hasAppliedOnce)) {
|
|
935
987
|
const { stdout, stderr, status } = runSpice(["apply"]);
|
|
936
988
|
if (status !== 0) logger.error(pc.red(`${CROSS} Spicetify apply failed:`), stdout, stderr);
|
|
@@ -951,16 +1003,32 @@ function wrapWithLoader({ config, cache, outFiles, server, dev = false, logger =
|
|
|
951
1003
|
name: namespace,
|
|
952
1004
|
setup(build$3) {
|
|
953
1005
|
if (build$3.initialOptions.write !== false) throw new Error(`[${namespace}] This plugin requires "write: false" in build options.`);
|
|
1006
|
+
build$3.onStart(() => {
|
|
1007
|
+
cache.changed.clear();
|
|
1008
|
+
cache.removed.clear();
|
|
1009
|
+
cache.hasChanges = false;
|
|
1010
|
+
});
|
|
954
1011
|
build$3.onEnd(async (res) => {
|
|
955
1012
|
try {
|
|
956
1013
|
if (res.errors.length > 0 || !res.outputFiles) return;
|
|
957
|
-
cache.changed.clear();
|
|
958
|
-
cache.hasChanges = false;
|
|
959
1014
|
const filesChanged = [];
|
|
960
1015
|
const outdir = resolve(build$3.initialOptions.outdir || "./dist");
|
|
961
1016
|
const bundledCss = getBundledCss(res.outputFiles, outdir, type, dev);
|
|
962
1017
|
const minify = build$3.initialOptions.minify;
|
|
963
1018
|
const slug = varSlugify(`${name}_${version}`);
|
|
1019
|
+
const currentFilePaths = /* @__PURE__ */ new Set();
|
|
1020
|
+
for (const file of res.outputFiles) {
|
|
1021
|
+
const isJs = file.path.endsWith(".js");
|
|
1022
|
+
const isCss = file.path.endsWith(".css");
|
|
1023
|
+
if (!dev && isCss && type === "extension") continue;
|
|
1024
|
+
const relPath = file.path.slice(outdir.length);
|
|
1025
|
+
const isCustomAppExtension = type === "custom-app" && isExtensionDir(relPath);
|
|
1026
|
+
let targetName;
|
|
1027
|
+
if (isJs) targetName = isCustomAppExtension ? outFiles.jsExtension ?? "extension.js" : outFiles.js;
|
|
1028
|
+
else if (isCss && !isCustomAppExtension) targetName = outFiles.css;
|
|
1029
|
+
if (targetName) currentFilePaths.add(join(outdir, targetName));
|
|
1030
|
+
}
|
|
1031
|
+
for (const cachedPath of cache.files.keys()) if (!currentFilePaths.has(cachedPath)) cache.removed.add(cachedPath);
|
|
964
1032
|
const transformPromises = res.outputFiles.map(async (file) => {
|
|
965
1033
|
const isJs = file.path.endsWith(".js");
|
|
966
1034
|
const isCss = file.path.endsWith(".css");
|
|
@@ -1073,14 +1141,15 @@ function wrapWithLoader({ config, cache, outFiles, server, dev = false, logger =
|
|
|
1073
1141
|
});
|
|
1074
1142
|
await Promise.all(transformPromises);
|
|
1075
1143
|
if (type === "custom-app") {
|
|
1076
|
-
const icon = config.icon;
|
|
1144
|
+
const icon = readFileSync(config.icon.default).toString();
|
|
1145
|
+
const activeIcon = config.icon.active ? readFileSync(config.icon.active).toString() : icon;
|
|
1077
1146
|
const manifestPath = join(outdir, "manifest.json");
|
|
1078
1147
|
const manifest = {
|
|
1079
1148
|
name: config.name,
|
|
1080
1149
|
subfiles: [],
|
|
1081
1150
|
subfiles_extension: ["extension.js"],
|
|
1082
|
-
icon
|
|
1083
|
-
|
|
1151
|
+
icon,
|
|
1152
|
+
activeIcon
|
|
1084
1153
|
};
|
|
1085
1154
|
const manifestString = JSON.stringify(manifest, null, 2);
|
|
1086
1155
|
const currentHash = createHash("md5").update(manifestString).digest("hex");
|
|
@@ -1119,8 +1188,9 @@ function getBundledCss(files, outdir, type, dev) {
|
|
|
1119
1188
|
//#region src/esbuild/plugins/index.ts
|
|
1120
1189
|
const plugins = {
|
|
1121
1190
|
css,
|
|
1122
|
-
|
|
1191
|
+
clean,
|
|
1123
1192
|
buildLogger,
|
|
1193
|
+
buildErrorReporter,
|
|
1124
1194
|
externalGlobal,
|
|
1125
1195
|
wrapWithLoader,
|
|
1126
1196
|
spicetifyHandler
|
|
@@ -1139,13 +1209,20 @@ const defaultBuildOptions = {
|
|
|
1139
1209
|
target: ["es2022", "chrome120"]
|
|
1140
1210
|
};
|
|
1141
1211
|
const getCommonPlugins = (opts) => {
|
|
1142
|
-
const { template, minify,
|
|
1212
|
+
const { template, minify, buildOptions, outFiles, server, dev } = opts;
|
|
1143
1213
|
const inline = !dev && template === "extension";
|
|
1144
|
-
|
|
1214
|
+
const cache = {
|
|
1215
|
+
files: /* @__PURE__ */ new Map(),
|
|
1216
|
+
changed: /* @__PURE__ */ new Set(),
|
|
1217
|
+
removed: /* @__PURE__ */ new Set(),
|
|
1218
|
+
hasChanges: true
|
|
1219
|
+
};
|
|
1220
|
+
const p = [
|
|
1145
1221
|
...plugins.css({
|
|
1146
1222
|
minify,
|
|
1147
1223
|
inline
|
|
1148
1224
|
}),
|
|
1225
|
+
plugins.clean(cache),
|
|
1149
1226
|
plugins.externalGlobal({
|
|
1150
1227
|
react: "Spicetify.React",
|
|
1151
1228
|
"react-dom": "Spicetify.ReactDOM",
|
|
@@ -1167,6 +1244,8 @@ const getCommonPlugins = (opts) => {
|
|
|
1167
1244
|
}),
|
|
1168
1245
|
plugins.buildLogger({ cache })
|
|
1169
1246
|
];
|
|
1247
|
+
if (dev) p.push(plugins.buildErrorReporter({ server }));
|
|
1248
|
+
return p;
|
|
1170
1249
|
};
|
|
1171
1250
|
function getEntryPoints(config) {
|
|
1172
1251
|
if (config.template === "theme") return [config.entry.js, config.entry.css];
|
|
@@ -1226,11 +1305,6 @@ function getJSBuildOptions(config, options) {
|
|
|
1226
1305
|
const entryPoints = getEntryPoints(config);
|
|
1227
1306
|
const minify = options.watch ? false : options.minify;
|
|
1228
1307
|
const outDir = resolve(config.outDir);
|
|
1229
|
-
const cache = {
|
|
1230
|
-
files: /* @__PURE__ */ new Map(),
|
|
1231
|
-
changed: /* @__PURE__ */ new Set(),
|
|
1232
|
-
hasChanges: true
|
|
1233
|
-
};
|
|
1234
1308
|
const outFiles = getOutFiles(config);
|
|
1235
1309
|
const overrides = {
|
|
1236
1310
|
...defaultBuildOptions,
|
|
@@ -1252,7 +1326,6 @@ function getJSBuildOptions(config, options) {
|
|
|
1252
1326
|
plugins: [...config.esbuildOptions?.plugins ? config.esbuildOptions.plugins : [], ...getCommonPlugins({
|
|
1253
1327
|
...config,
|
|
1254
1328
|
minify,
|
|
1255
|
-
cache,
|
|
1256
1329
|
buildOptions: {
|
|
1257
1330
|
apply: options.apply,
|
|
1258
1331
|
copy: options.copy,
|
|
@@ -1357,10 +1430,16 @@ function createPackageJSON(options) {
|
|
|
1357
1430
|
dependencies: {},
|
|
1358
1431
|
devDependencies: { "@spicetify/creator": "latest" }
|
|
1359
1432
|
};
|
|
1360
|
-
if (options.language === "ts")
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1433
|
+
if (options.language === "ts") {
|
|
1434
|
+
result.devDependencies = {
|
|
1435
|
+
...result.devDependencies,
|
|
1436
|
+
...options.packageManager === "bun" ? { "@types/bun": "^1.3.10" } : { "@types/node": "^25.5.0" }
|
|
1437
|
+
};
|
|
1438
|
+
result.peerDependencies = {
|
|
1439
|
+
...result.peerDependencies,
|
|
1440
|
+
typescript: "^5"
|
|
1441
|
+
};
|
|
1442
|
+
}
|
|
1364
1443
|
const slices = [FRAMEWORKS$1[options.framework], LINTERS$1[options.linter]];
|
|
1365
1444
|
Object.values(INTERSECTIONS).forEach((intersection) => {
|
|
1366
1445
|
if (intersection.condition(options)) slices.push(intersection);
|
|
@@ -1429,7 +1508,7 @@ const SHARED_FILES = (opts) => {
|
|
|
1429
1508
|
{
|
|
1430
1509
|
from: "DOT-gitignore",
|
|
1431
1510
|
to: ".gitignore",
|
|
1432
|
-
isShared
|
|
1511
|
+
isShared
|
|
1433
1512
|
},
|
|
1434
1513
|
{
|
|
1435
1514
|
from: `spice.config.${ext(opts.language)}`,
|
|
@@ -1477,11 +1556,23 @@ const LANGUAGE_FILES = {
|
|
|
1477
1556
|
to: "jsconfig.json",
|
|
1478
1557
|
isShared: true
|
|
1479
1558
|
}],
|
|
1480
|
-
ts: [
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1559
|
+
ts: [
|
|
1560
|
+
{
|
|
1561
|
+
from: "tsconfig.json",
|
|
1562
|
+
to: "tsconfig.json",
|
|
1563
|
+
isShared: true
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
from: "tsconfig.app.json",
|
|
1567
|
+
to: "tsconfig.app.json",
|
|
1568
|
+
isShared: true
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
from: "tsconfig.node.json",
|
|
1572
|
+
to: "tsconfig.node.json",
|
|
1573
|
+
isShared: true
|
|
1574
|
+
}
|
|
1575
|
+
]
|
|
1485
1576
|
};
|
|
1486
1577
|
const FRAMEWORKS = {
|
|
1487
1578
|
react: ({ language, template }) => {
|
|
@@ -1647,7 +1738,7 @@ function tryGitInit(root) {
|
|
|
1647
1738
|
const downloads = { spicetify: {
|
|
1648
1739
|
from: "https://raw.githubusercontent.com/spicetify/cli/main/globals.d.ts",
|
|
1649
1740
|
to: "./src/types/spicetify.d.ts",
|
|
1650
|
-
action: (content) => content.replace("const React: any;", "const React: typeof import(\"react\");").replace("const ReactDOM: any;", "const ReactDOM: typeof import(\"react-dom/client\");").replace("const ReactDOMServer: any;", "const ReactDOMServer: typeof import(\"react-dom/server\");")
|
|
1741
|
+
action: (content) => content.replace("const React: any;", "const React: typeof import(\"react\");").replace("const ReactDOM: any;", "const ReactDOM: typeof import(\"react-dom/client\");").replace("const ReactJSX: any;", "const ReactJSX: typeof import(\"react/jsx-runtime\");").replace("const ReactDOMServer: any;", "const ReactDOMServer: typeof import(\"react-dom/server\");")
|
|
1651
1742
|
} };
|
|
1652
1743
|
async function updateTypes(isUpdating = true, cwd = process.cwd()) {
|
|
1653
1744
|
const s = spinner();
|
|
@@ -1959,7 +2050,7 @@ async function createHmrServer(config, logger = createLogger("hmrServer")) {
|
|
|
1959
2050
|
});
|
|
1960
2051
|
});
|
|
1961
2052
|
function broadcast(data) {
|
|
1962
|
-
const message =
|
|
2053
|
+
const message = JSON.stringify(data);
|
|
1963
2054
|
for (const client of clients) if (client.readyState === WebSocket.OPEN) client.send(message);
|
|
1964
2055
|
}
|
|
1965
2056
|
return {
|
|
@@ -2032,7 +2123,8 @@ const injectHMRExtension = async (rootLink, wsLink, outFiles) => {
|
|
|
2032
2123
|
_SERVER_URL: JSON.stringify(rootLink),
|
|
2033
2124
|
_HOT_RELOAD_LINK: JSON.stringify(wsLink),
|
|
2034
2125
|
_JS_PATH: JSON.stringify(`/files/${outFiles.js}`),
|
|
2035
|
-
_CSS_PATH: JSON.stringify(outFiles.css ? `/files/${outFiles.css}` : `/files/app.css`)
|
|
2126
|
+
_CSS_PATH: JSON.stringify(outFiles.css ? `/files/${outFiles.css}` : `/files/app.css`),
|
|
2127
|
+
_REMOVE_CMD: JSON.stringify(`spicetify config extensions sc-live-reload-helper.js- && spicetify apply`)
|
|
2036
2128
|
}
|
|
2037
2129
|
});
|
|
2038
2130
|
writeFileSync(outDir, code);
|
|
@@ -2082,56 +2174,20 @@ const injectHMRCustomApp = async (rootLink, wsLink, outFiles, config) => {
|
|
|
2082
2174
|
mkdirp(destDir);
|
|
2083
2175
|
const indexJsPath = resolve(destDir, "index.js");
|
|
2084
2176
|
const extensionJsPath = resolve(destDir, outFiles.jsExtension ?? "extension.js");
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
return null;
|
|
2092
|
-
});
|
|
2093
|
-
};
|
|
2094
|
-
|
|
2095
|
-
const AppWrapper = ({ appPromise }) => {
|
|
2096
|
-
const [App, setApp] = React.useState(null);
|
|
2097
|
-
|
|
2098
|
-
React.useEffect(() => {
|
|
2099
|
-
let mounted = true;
|
|
2100
|
-
|
|
2101
|
-
appPromise.then((app) => {
|
|
2102
|
-
if (mounted && app) {
|
|
2103
|
-
setApp(() => app);
|
|
2104
|
-
}
|
|
2105
|
-
});
|
|
2106
|
-
|
|
2107
|
-
return () => {
|
|
2108
|
-
mounted = false;
|
|
2109
|
-
};
|
|
2110
|
-
}, [appPromise]);
|
|
2111
|
-
|
|
2112
|
-
if (!App) {
|
|
2113
|
-
return React.createElement(
|
|
2114
|
-
"div",
|
|
2115
|
-
{ className: "loading" },
|
|
2116
|
-
"Loading app..."
|
|
2117
|
-
);
|
|
2118
|
-
}
|
|
2119
|
-
|
|
2120
|
-
return React.createElement(App);
|
|
2121
|
-
};
|
|
2122
|
-
|
|
2123
|
-
const render = () => {
|
|
2124
|
-
const appPromise = waitForImport();
|
|
2125
|
-
return React.createElement(AppWrapper, { appPromise });
|
|
2126
|
-
};
|
|
2127
|
-
`);
|
|
2177
|
+
const { code: transformedIndexCode } = await transform(readFileSync(hmrCustomAppFilePath, "utf8"), {
|
|
2178
|
+
loader: "js",
|
|
2179
|
+
define: { _IMPORT_LINK: JSON.stringify(`${rootLink}/files/${outFiles.js}`) },
|
|
2180
|
+
platform: "browser"
|
|
2181
|
+
});
|
|
2182
|
+
writeFileSync(indexJsPath, transformedIndexCode);
|
|
2128
2183
|
const { code: extensionCode } = await transform(readFileSync(liveReloadFilePath, "utf8"), {
|
|
2129
2184
|
loader: "js",
|
|
2130
2185
|
define: {
|
|
2131
2186
|
_SERVER_URL: JSON.stringify(rootLink),
|
|
2132
2187
|
_HOT_RELOAD_LINK: JSON.stringify(wsLink),
|
|
2133
2188
|
_JS_PATH: JSON.stringify(`/files/${outFiles.jsExtension ?? "extension.js"}`),
|
|
2134
|
-
_CSS_PATH: JSON.stringify(outFiles.css ? `/files/${outFiles.css}` : `/files/app.css`)
|
|
2189
|
+
_CSS_PATH: JSON.stringify(outFiles.css ? `/files/${outFiles.css}` : `/files/app.css`),
|
|
2190
|
+
_REMOVE_CMD: JSON.stringify(`spicetify config custom_apps ${customAppId}- && spicetify apply`)
|
|
2135
2191
|
}
|
|
2136
2192
|
});
|
|
2137
2193
|
writeFileSync(extensionJsPath, extensionCode);
|
|
@@ -2204,11 +2260,6 @@ async function dev$1(options) {
|
|
|
2204
2260
|
function getJSDevOptions(config, options) {
|
|
2205
2261
|
const entryPoints = getEntryPoints(config);
|
|
2206
2262
|
const minify = false;
|
|
2207
|
-
const cache = {
|
|
2208
|
-
files: /* @__PURE__ */ new Map(),
|
|
2209
|
-
changed: /* @__PURE__ */ new Set(),
|
|
2210
|
-
hasChanges: true
|
|
2211
|
-
};
|
|
2212
2263
|
const overrides = {
|
|
2213
2264
|
...defaultBuildOptions,
|
|
2214
2265
|
outdir: outDir,
|
|
@@ -2227,7 +2278,6 @@ function getJSDevOptions(config, options) {
|
|
|
2227
2278
|
plugins: [...config.esbuildOptions?.plugins ? config.esbuildOptions.plugins : [], ...getCommonPlugins({
|
|
2228
2279
|
...config,
|
|
2229
2280
|
minify,
|
|
2230
|
-
cache,
|
|
2231
2281
|
buildOptions: {
|
|
2232
2282
|
copy: true,
|
|
2233
2283
|
apply: false,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
1
2
|
import { defineConfig } from "@spicetify/creator";
|
|
2
3
|
|
|
3
4
|
// Learn more: {{config-reference-link}}
|
|
@@ -7,4 +8,9 @@ export default defineConfig({
|
|
|
7
8
|
linter: "{{linter}}",
|
|
8
9
|
template: "{{template}}",
|
|
9
10
|
packageManager: "{{package-manager}}",
|
|
11
|
+
esbuildOptions: {
|
|
12
|
+
alias: {
|
|
13
|
+
"@": resolve(__dirname, "src"),
|
|
14
|
+
},
|
|
15
|
+
},
|
|
10
16
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
1
2
|
import { defineConfig } from "@spicetify/creator";
|
|
2
3
|
|
|
3
4
|
// Learn more: {{config-reference-link}}
|
|
@@ -7,4 +8,9 @@ export default defineConfig({
|
|
|
7
8
|
linter: "{{linter}}",
|
|
8
9
|
template: "{{template}}",
|
|
9
10
|
packageManager: "{{package-manager}}",
|
|
11
|
+
esbuildOptions: {
|
|
12
|
+
alias: {
|
|
13
|
+
"@": resolve(__dirname, "src"),
|
|
14
|
+
},
|
|
15
|
+
},
|
|
10
16
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"types": ["@spicetify/creator/client"],
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
|
|
10
|
+
/* Bundler mode */
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"allowImportingTsExtensions": true,
|
|
13
|
+
"verbatimModuleSyntax": true,
|
|
14
|
+
"moduleDetection": "force",
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
"jsx": "react-jsx",
|
|
17
|
+
|
|
18
|
+
/* Linting */
|
|
19
|
+
"strict": true,
|
|
20
|
+
"noUnusedLocals": true,
|
|
21
|
+
"noUnusedParameters": true,
|
|
22
|
+
"erasableSyntaxOnly": true,
|
|
23
|
+
"noFallthroughCasesInSwitch": true,
|
|
24
|
+
"noUncheckedSideEffectImports": true,
|
|
25
|
+
|
|
26
|
+
// Paths
|
|
27
|
+
"baseUrl": ".",
|
|
28
|
+
"paths": {
|
|
29
|
+
"@/*": ["./src/*"]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"include": ["src"]
|
|
33
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2023",
|
|
4
|
+
"lib": ["ES2023"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"types": ["node"],
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
|
|
9
|
+
/* Bundler mode */
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"verbatimModuleSyntax": true,
|
|
13
|
+
"moduleDetection": "force",
|
|
14
|
+
"noEmit": true,
|
|
15
|
+
|
|
16
|
+
/* Linting */
|
|
17
|
+
"strict": true,
|
|
18
|
+
"noUnusedLocals": true,
|
|
19
|
+
"noUnusedParameters": true,
|
|
20
|
+
"erasableSyntaxOnly": true,
|
|
21
|
+
"noFallthroughCasesInSwitch": true,
|
|
22
|
+
"noUncheckedSideEffectImports": true
|
|
23
|
+
},
|
|
24
|
+
"include": ["spice.config.ts"]
|
|
25
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "@/extension/app.css";
|
|
2
2
|
import { createRoot } from "react-dom/client";
|
|
3
|
-
// you can use aliases too ! (
|
|
3
|
+
// you can use aliases too ! (checkout tsconfig.app.json)
|
|
4
4
|
import Onboarding from "@/components/Onboarding";
|
|
5
5
|
|
|
6
6
|
const config = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "@/app.css";
|
|
2
2
|
import { createRoot } from "react-dom/client";
|
|
3
|
-
// you can use aliases too ! (
|
|
3
|
+
// you can use aliases too ! (checkout tsconfig.app.json)
|
|
4
4
|
import OnboardingCard from "@/components/Onboarding";
|
|
5
5
|
|
|
6
6
|
const config = {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
1
2
|
import { defineConfig } from "@spicetify/creator";
|
|
2
3
|
|
|
3
4
|
// Learn more: {{config-reference-link}}
|
|
@@ -7,4 +8,9 @@ export default defineConfig({
|
|
|
7
8
|
linter: "{{linter}}",
|
|
8
9
|
template: "{{template}}",
|
|
9
10
|
packageManager: "{{package-manager}}",
|
|
11
|
+
esbuildOptions: {
|
|
12
|
+
alias: {
|
|
13
|
+
"@": resolve(__dirname, "src"),
|
|
14
|
+
},
|
|
15
|
+
},
|
|
10
16
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolve } from "path";
|
|
1
2
|
import { defineConfig } from "@spicetify/creator";
|
|
2
3
|
|
|
3
4
|
// Learn more: {{config-reference-link}}
|
|
@@ -7,4 +8,9 @@ export default defineConfig({
|
|
|
7
8
|
linter: "{{linter}}",
|
|
8
9
|
template: "{{template}}",
|
|
9
10
|
packageManager: "{{package-manager}}",
|
|
11
|
+
esbuildOptions: {
|
|
12
|
+
alias: {
|
|
13
|
+
"@": resolve(__dirname, "src"),
|
|
14
|
+
},
|
|
15
|
+
},
|
|
10
16
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"types": ["@spicetify/creator/client"],
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
|
|
10
|
+
/* Bundler mode */
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"allowImportingTsExtensions": true,
|
|
13
|
+
"verbatimModuleSyntax": true,
|
|
14
|
+
"moduleDetection": "force",
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
"jsx": "react-jsx",
|
|
17
|
+
|
|
18
|
+
/* Linting */
|
|
19
|
+
"strict": true,
|
|
20
|
+
"noUnusedLocals": true,
|
|
21
|
+
"noUnusedParameters": true,
|
|
22
|
+
"erasableSyntaxOnly": true,
|
|
23
|
+
"noFallthroughCasesInSwitch": true,
|
|
24
|
+
"noUncheckedSideEffectImports": true,
|
|
25
|
+
|
|
26
|
+
// Paths
|
|
27
|
+
"baseUrl": ".",
|
|
28
|
+
"paths": {
|
|
29
|
+
"@/*": ["./src/*"]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"include": ["src"]
|
|
33
|
+
}
|