@spicemod/creator 0.0.26 → 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.
Files changed (40) hide show
  1. package/dist/bin.mjs +165 -116
  2. package/dist/templates/custom-app/shared/spice.config.js +6 -0
  3. package/dist/templates/custom-app/shared/spice.config.ts +6 -0
  4. package/dist/templates/custom-app/shared/tsconfig.app.json +33 -0
  5. package/dist/templates/custom-app/shared/tsconfig.node.json +25 -0
  6. package/dist/templates/custom-app/ts/react/src/extension/index.tsx +1 -1
  7. package/dist/templates/extension/js/react/src/app.jsx +1 -1
  8. package/dist/templates/extension/shared/spice.config.js +6 -0
  9. package/dist/templates/extension/shared/spice.config.ts +6 -0
  10. package/dist/templates/extension/shared/tsconfig.app.json +33 -0
  11. package/dist/templates/extension/shared/tsconfig.node.json +25 -0
  12. package/dist/templates/extension/ts/react/src/app.tsx +1 -1
  13. package/dist/templates/hmrCustomApp.js +284 -0
  14. package/dist/templates/liveReload.js +298 -45
  15. package/dist/templates/theme/js/react/src/app.jsx +1 -1
  16. package/dist/templates/theme/shared/spice.config.js +6 -0
  17. package/dist/templates/theme/shared/spice.config.ts +6 -0
  18. package/dist/templates/theme/shared/tsconfig.app.json +33 -0
  19. package/dist/templates/theme/shared/tsconfig.node.json +25 -0
  20. package/dist/templates/theme/ts/react/src/app.tsx +1 -1
  21. package/package.json +1 -1
  22. package/templates/custom-app/shared/spice.config.js +6 -0
  23. package/templates/custom-app/shared/spice.config.ts +6 -0
  24. package/templates/custom-app/shared/tsconfig.app.json +33 -0
  25. package/templates/custom-app/shared/tsconfig.node.json +25 -0
  26. package/templates/custom-app/ts/react/src/extension/index.tsx +1 -1
  27. package/templates/extension/js/react/src/app.jsx +1 -1
  28. package/templates/extension/shared/spice.config.js +6 -0
  29. package/templates/extension/shared/spice.config.ts +6 -0
  30. package/templates/extension/shared/tsconfig.app.json +33 -0
  31. package/templates/extension/shared/tsconfig.node.json +25 -0
  32. package/templates/extension/ts/react/src/app.tsx +1 -1
  33. package/templates/hmrCustomApp.js +284 -0
  34. package/templates/liveReload.js +298 -45
  35. package/templates/theme/js/react/src/app.jsx +1 -1
  36. package/templates/theme/shared/spice.config.js +6 -0
  37. package/templates/theme/shared/spice.config.ts +6 -0
  38. package/templates/theme/shared/tsconfig.app.json +33 -0
  39. package/templates/theme/shared/tsconfig.node.json +25 -0
  40. 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.26";
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/cleanDist.ts
783
- const cleanDist = (outDir) => ({
784
- name: "spice_internal__clean-dist",
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(outDir)) rmSync(outDir, {
788
- recursive: true,
789
- force: true
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
- if (!cache.hasChanges || cache.changed.size === 0) return;
863
- const tasks = [];
864
- for (const filePath of cache.changed) {
865
- const fileData = cache.files.get(filePath);
866
- if (!fileData) continue;
867
- const targetPath = resolve(outDir, basename(filePath));
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
- if (!cache.hasChanges || cache.changed.size === 0) return;
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 Promise.all(tasks);
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");
@@ -1120,8 +1188,9 @@ function getBundledCss(files, outdir, type, dev) {
1120
1188
  //#region src/esbuild/plugins/index.ts
1121
1189
  const plugins = {
1122
1190
  css,
1123
- cleanDist,
1191
+ clean,
1124
1192
  buildLogger,
1193
+ buildErrorReporter,
1125
1194
  externalGlobal,
1126
1195
  wrapWithLoader,
1127
1196
  spicetifyHandler
@@ -1140,13 +1209,20 @@ const defaultBuildOptions = {
1140
1209
  target: ["es2022", "chrome120"]
1141
1210
  };
1142
1211
  const getCommonPlugins = (opts) => {
1143
- const { template, minify, cache, buildOptions, outFiles, server, dev } = opts;
1212
+ const { template, minify, buildOptions, outFiles, server, dev } = opts;
1144
1213
  const inline = !dev && template === "extension";
1145
- return [
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 = [
1146
1221
  ...plugins.css({
1147
1222
  minify,
1148
1223
  inline
1149
1224
  }),
1225
+ plugins.clean(cache),
1150
1226
  plugins.externalGlobal({
1151
1227
  react: "Spicetify.React",
1152
1228
  "react-dom": "Spicetify.ReactDOM",
@@ -1168,6 +1244,8 @@ const getCommonPlugins = (opts) => {
1168
1244
  }),
1169
1245
  plugins.buildLogger({ cache })
1170
1246
  ];
1247
+ if (dev) p.push(plugins.buildErrorReporter({ server }));
1248
+ return p;
1171
1249
  };
1172
1250
  function getEntryPoints(config) {
1173
1251
  if (config.template === "theme") return [config.entry.js, config.entry.css];
@@ -1227,11 +1305,6 @@ function getJSBuildOptions(config, options) {
1227
1305
  const entryPoints = getEntryPoints(config);
1228
1306
  const minify = options.watch ? false : options.minify;
1229
1307
  const outDir = resolve(config.outDir);
1230
- const cache = {
1231
- files: /* @__PURE__ */ new Map(),
1232
- changed: /* @__PURE__ */ new Set(),
1233
- hasChanges: true
1234
- };
1235
1308
  const outFiles = getOutFiles(config);
1236
1309
  const overrides = {
1237
1310
  ...defaultBuildOptions,
@@ -1253,7 +1326,6 @@ function getJSBuildOptions(config, options) {
1253
1326
  plugins: [...config.esbuildOptions?.plugins ? config.esbuildOptions.plugins : [], ...getCommonPlugins({
1254
1327
  ...config,
1255
1328
  minify,
1256
- cache,
1257
1329
  buildOptions: {
1258
1330
  apply: options.apply,
1259
1331
  copy: options.copy,
@@ -1358,10 +1430,16 @@ function createPackageJSON(options) {
1358
1430
  dependencies: {},
1359
1431
  devDependencies: { "@spicetify/creator": "latest" }
1360
1432
  };
1361
- if (options.language === "ts") result.peerDependencies = {
1362
- ...result.peerDependencies,
1363
- typescript: "^5"
1364
- };
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
+ }
1365
1443
  const slices = [FRAMEWORKS$1[options.framework], LINTERS$1[options.linter]];
1366
1444
  Object.values(INTERSECTIONS).forEach((intersection) => {
1367
1445
  if (intersection.condition(options)) slices.push(intersection);
@@ -1430,7 +1508,7 @@ const SHARED_FILES = (opts) => {
1430
1508
  {
1431
1509
  from: "DOT-gitignore",
1432
1510
  to: ".gitignore",
1433
- isShared: true
1511
+ isShared
1434
1512
  },
1435
1513
  {
1436
1514
  from: `spice.config.${ext(opts.language)}`,
@@ -1478,11 +1556,23 @@ const LANGUAGE_FILES = {
1478
1556
  to: "jsconfig.json",
1479
1557
  isShared: true
1480
1558
  }],
1481
- ts: [{
1482
- from: "tsconfig.json",
1483
- to: "tsconfig.json",
1484
- isShared: true
1485
- }]
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
+ ]
1486
1576
  };
1487
1577
  const FRAMEWORKS = {
1488
1578
  react: ({ language, template }) => {
@@ -1648,7 +1738,7 @@ function tryGitInit(root) {
1648
1738
  const downloads = { spicetify: {
1649
1739
  from: "https://raw.githubusercontent.com/spicetify/cli/main/globals.d.ts",
1650
1740
  to: "./src/types/spicetify.d.ts",
1651
- 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\");")
1652
1742
  } };
1653
1743
  async function updateTypes(isUpdating = true, cwd = process.cwd()) {
1654
1744
  const s = spinner();
@@ -1960,7 +2050,7 @@ async function createHmrServer(config, logger = createLogger("hmrServer")) {
1960
2050
  });
1961
2051
  });
1962
2052
  function broadcast(data) {
1963
- const message = typeof data === "string" ? data : JSON.stringify(data);
2053
+ const message = JSON.stringify(data);
1964
2054
  for (const client of clients) if (client.readyState === WebSocket.OPEN) client.send(message);
1965
2055
  }
1966
2056
  return {
@@ -2033,7 +2123,8 @@ const injectHMRExtension = async (rootLink, wsLink, outFiles) => {
2033
2123
  _SERVER_URL: JSON.stringify(rootLink),
2034
2124
  _HOT_RELOAD_LINK: JSON.stringify(wsLink),
2035
2125
  _JS_PATH: JSON.stringify(`/files/${outFiles.js}`),
2036
- _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`)
2037
2128
  }
2038
2129
  });
2039
2130
  writeFileSync(outDir, code);
@@ -2083,56 +2174,20 @@ const injectHMRCustomApp = async (rootLink, wsLink, outFiles, config) => {
2083
2174
  mkdirp(destDir);
2084
2175
  const indexJsPath = resolve(destDir, "index.js");
2085
2176
  const extensionJsPath = resolve(destDir, outFiles.jsExtension ?? "extension.js");
2086
- writeFileSync(indexJsPath, `const React = Spicetify.React;
2087
- const waitForImport = () => {
2088
- return import("${rootLink}/files/${outFiles.js}")
2089
- .then((mod) => mod.default || mod.render)
2090
- .catch((err) => {
2091
- console.error("Failed to import app:", err);
2092
- return null;
2093
- });
2094
- };
2095
-
2096
- const AppWrapper = ({ appPromise }) => {
2097
- const [App, setApp] = React.useState(null);
2098
-
2099
- React.useEffect(() => {
2100
- let mounted = true;
2101
-
2102
- appPromise.then((app) => {
2103
- if (mounted && app) {
2104
- setApp(() => app);
2105
- }
2106
- });
2107
-
2108
- return () => {
2109
- mounted = false;
2110
- };
2111
- }, [appPromise]);
2112
-
2113
- if (!App) {
2114
- return React.createElement(
2115
- "div",
2116
- { className: "loading" },
2117
- "Loading app..."
2118
- );
2119
- }
2120
-
2121
- return React.createElement(App);
2122
- };
2123
-
2124
- const render = () => {
2125
- const appPromise = waitForImport();
2126
- return React.createElement(AppWrapper, { appPromise });
2127
- };
2128
- `);
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);
2129
2183
  const { code: extensionCode } = await transform(readFileSync(liveReloadFilePath, "utf8"), {
2130
2184
  loader: "js",
2131
2185
  define: {
2132
2186
  _SERVER_URL: JSON.stringify(rootLink),
2133
2187
  _HOT_RELOAD_LINK: JSON.stringify(wsLink),
2134
2188
  _JS_PATH: JSON.stringify(`/files/${outFiles.jsExtension ?? "extension.js"}`),
2135
- _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`)
2136
2191
  }
2137
2192
  });
2138
2193
  writeFileSync(extensionJsPath, extensionCode);
@@ -2205,11 +2260,6 @@ async function dev$1(options) {
2205
2260
  function getJSDevOptions(config, options) {
2206
2261
  const entryPoints = getEntryPoints(config);
2207
2262
  const minify = false;
2208
- const cache = {
2209
- files: /* @__PURE__ */ new Map(),
2210
- changed: /* @__PURE__ */ new Set(),
2211
- hasChanges: true
2212
- };
2213
2263
  const overrides = {
2214
2264
  ...defaultBuildOptions,
2215
2265
  outdir: outDir,
@@ -2228,7 +2278,6 @@ function getJSDevOptions(config, options) {
2228
2278
  plugins: [...config.esbuildOptions?.plugins ? config.esbuildOptions.plugins : [], ...getCommonPlugins({
2229
2279
  ...config,
2230
2280
  minify,
2231
- cache,
2232
2281
  buildOptions: {
2233
2282
  copy: true,
2234
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 ! (just add them to tsconfig.json)
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 ! (just add them to tsconfig.json)
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
+ }
@@ -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 "@/app.css";
2
2
  import { createRoot } from "react-dom/client";
3
- // you can use aliases too ! (just add them to tsconfig.json)
3
+ // you can use aliases too ! (checkout tsconfig.app.json)
4
4
  import Onboarding from "@/components/Onboarding";
5
5
 
6
6
  const config = {