setupTypeScript.js raw

   1  // @ts-check
   2  
   3  /** This script modifies the project to support TS code in .svelte files like:
   4  
   5    <script lang="ts">
   6    	export let name: string;
   7    </script>
   8   
   9    As well as validating the code for CI.
  10    */
  11  
  12  /**  To work on this script:
  13    rm -rf test-template template && git clone sveltejs/template test-template && node scripts/setupTypeScript.js test-template
  14  */
  15  
  16  import fs from "fs";
  17  import path from "path";
  18  import { argv } from "process";
  19  import url from "url";
  20  
  21  const __filename = url.fileURLToPath(import.meta.url);
  22  const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
  23  const projectRoot = argv[2] || path.join(__dirname, "..");
  24  
  25  // Add deps to pkg.json
  26  const packageJSON = JSON.parse(
  27    fs.readFileSync(path.join(projectRoot, "package.json"), "utf8"),
  28  );
  29  packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, {
  30    "svelte-check": "^3.0.0",
  31    "svelte-preprocess": "^5.0.0",
  32    "@rollup/plugin-typescript": "^11.0.0",
  33    typescript: "^4.9.0",
  34    tslib: "^2.5.0",
  35    "@tsconfig/svelte": "^3.0.0",
  36  });
  37  
  38  // Add script for checking
  39  packageJSON.scripts = Object.assign(packageJSON.scripts, {
  40    check: "svelte-check",
  41  });
  42  
  43  // Write the package JSON
  44  fs.writeFileSync(
  45    path.join(projectRoot, "package.json"),
  46    JSON.stringify(packageJSON, null, "  "),
  47  );
  48  
  49  // mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too
  50  const beforeMainJSPath = path.join(projectRoot, "src", "main.js");
  51  const afterMainTSPath = path.join(projectRoot, "src", "main.ts");
  52  fs.renameSync(beforeMainJSPath, afterMainTSPath);
  53  
  54  // Switch the app.svelte file to use TS
  55  const appSveltePath = path.join(projectRoot, "src", "App.svelte");
  56  let appFile = fs.readFileSync(appSveltePath, "utf8");
  57  appFile = appFile.replace("<script>", '<script lang="ts">');
  58  appFile = appFile.replace("export let name;", "export let name: string;");
  59  fs.writeFileSync(appSveltePath, appFile);
  60  
  61  // Edit rollup config
  62  const rollupConfigPath = path.join(projectRoot, "rollup.config.js");
  63  let rollupConfig = fs.readFileSync(rollupConfigPath, "utf8");
  64  
  65  // Edit imports
  66  rollupConfig = rollupConfig.replace(
  67    `'rollup-plugin-css-only';`,
  68    `'rollup-plugin-css-only';
  69  import sveltePreprocess from 'svelte-preprocess';
  70  import typescript from '@rollup/plugin-typescript';`,
  71  );
  72  
  73  // Replace name of entry point
  74  rollupConfig = rollupConfig.replace(`'src/main.js'`, `'src/main.ts'`);
  75  
  76  // Add preprocessor
  77  rollupConfig = rollupConfig.replace(
  78    "compilerOptions:",
  79    "preprocess: sveltePreprocess({ sourceMap: !production }),\n\t\t\tcompilerOptions:",
  80  );
  81  
  82  // Add TypeScript
  83  rollupConfig = rollupConfig.replace(
  84    "commonjs(),",
  85    "commonjs(),\n\t\ttypescript({\n\t\t\tsourceMap: !production,\n\t\t\tinlineSources: !production\n\t\t}),",
  86  );
  87  fs.writeFileSync(rollupConfigPath, rollupConfig);
  88  
  89  // Add svelte.config.js
  90  const tsconfig = `{
  91    "extends": "@tsconfig/svelte/tsconfig.json",
  92  
  93    "include": ["src/**/*"],
  94    "exclude": ["node_modules/*", "__sapper__/*", "public/*"]
  95  }`;
  96  const tsconfigPath = path.join(projectRoot, "tsconfig.json");
  97  fs.writeFileSync(tsconfigPath, tsconfig);
  98  
  99  // Add TSConfig
 100  const svelteConfig = `import sveltePreprocess from 'svelte-preprocess';
 101  
 102  export default {
 103    preprocess: sveltePreprocess()
 104  };
 105  `;
 106  const svelteConfigPath = path.join(projectRoot, "svelte.config.js");
 107  fs.writeFileSync(svelteConfigPath, svelteConfig);
 108  
 109  // Add global.d.ts
 110  const dtsPath = path.join(projectRoot, "src", "global.d.ts");
 111  fs.writeFileSync(dtsPath, `/// <reference types="svelte" />`);
 112  
 113  // Delete this script, but not during testing
 114  if (!argv[2]) {
 115    // Remove the script
 116    fs.unlinkSync(path.join(__filename));
 117  
 118    // Check for Mac's DS_store file, and if it's the only one left remove it
 119    const remainingFiles = fs.readdirSync(path.join(__dirname));
 120    if (remainingFiles.length === 1 && remainingFiles[0] === ".DS_store") {
 121      fs.unlinkSync(path.join(__dirname, ".DS_store"));
 122    }
 123  
 124    // Check if the scripts folder is empty
 125    if (fs.readdirSync(path.join(__dirname)).length === 0) {
 126      // Remove the scripts folder
 127      fs.rmdirSync(path.join(__dirname));
 128    }
 129  }
 130  
 131  // Adds the extension recommendation
 132  fs.mkdirSync(path.join(projectRoot, ".vscode"), { recursive: true });
 133  fs.writeFileSync(
 134    path.join(projectRoot, ".vscode", "extensions.json"),
 135    `{
 136    "recommendations": ["svelte.svelte-vscode"]
 137  }
 138  `,
 139  );
 140  
 141  console.log("Converted to TypeScript.");
 142  
 143  if (fs.existsSync(path.join(projectRoot, "node_modules"))) {
 144    console.log(
 145      "\nYou will need to re-run your dependency manager to get started.",
 146    );
 147  }
 148