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