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