diff --git a/.changeset/new-walls-prove.md b/.changeset/new-walls-prove.md new file mode 100644 index 000000000000..5ce23ab0303d --- /dev/null +++ b/.changeset/new-walls-prove.md @@ -0,0 +1,5 @@ +--- +'create-svelte': patch +--- + +Remove CSS option and simplify diff --git a/packages/create-svelte/.gitignore b/packages/create-svelte/.gitignore index 8665020bf991..7e1457c65914 100644 --- a/packages/create-svelte/.gitignore +++ b/packages/create-svelte/.gitignore @@ -1,4 +1,5 @@ -/bin +/bin.js +/dist # re-enable this once we're out of prerelease /cli/versions.js \ No newline at end of file diff --git a/packages/create-svelte/cli/global.d.ts b/packages/create-svelte/cli/global.d.ts index 639895aac9bc..271d59added9 100644 --- a/packages/create-svelte/cli/global.d.ts +++ b/packages/create-svelte/cli/global.d.ts @@ -1,11 +1,5 @@ -declare module '*.gitignore'; - -declare module 'gitignore-parser'; - declare module 'prompts/lib/index'; -declare module 'tiny-glob/sync'; - declare module '*.json'; // TODO make this depend on the real types from the kit package diff --git a/packages/create-svelte/cli/index.js b/packages/create-svelte/cli/index.js index f17d7e881cac..34596ca5a53a 100644 --- a/packages/create-svelte/cli/index.js +++ b/packages/create-svelte/cli/index.js @@ -1,18 +1,11 @@ //eslint-disable-next-line import/no-unresolved -import { mkdirp } from '@sveltejs/kit/filesystem'; import fs from 'fs'; -import parser from 'gitignore-parser'; -import { bold, cyan, gray, green, red } from 'kleur/colors'; import path from 'path'; +import { mkdirp } from '@sveltejs/kit/filesystem'; // eslint-disable-line +import { bold, cyan, gray, green, red } from 'kleur/colors'; import prompts from 'prompts/lib/index'; -import glob from 'tiny-glob/sync.js'; -import gitignore_contents from '../template/.gitignore'; -import add_css from './modifications/add_css'; -import add_typescript from './modifications/add_typescript'; -// import versions from './versions'; +import { fileURLToPath } from 'url'; import { version } from '../package.json'; -import add_prettier from './modifications/add_prettier'; -import add_eslint from './modifications/add_eslint'; const disclaimer = ` Welcome to the SvelteKit setup wizard! @@ -25,10 +18,10 @@ async function main() { console.log(gray(`\ncreate-svelte version ${version}`)); console.log(red(disclaimer)); - const target = process.argv[2] || '.'; + const cwd = process.argv[2] || '.'; - if (fs.existsSync(target)) { - if (fs.readdirSync(target).length > 0) { + if (fs.existsSync(cwd)) { + if (fs.readdirSync(cwd).length > 0) { const response = await prompts({ type: 'confirm', name: 'value', @@ -41,40 +34,70 @@ async function main() { } } } else { - mkdirp(target); + mkdirp(cwd); } - const cwd = path.join(__dirname, 'template'); - const gitignore = parser.compile(gitignore_contents); - - const files = glob('**/*', { cwd }).filter(gitignore.accepts); - - files.forEach((file) => { - const src = path.join(cwd, file); - const dest = path.join(target, file); - - if (fs.statSync(src).isDirectory()) { - mkdirp(dest); - } else { - fs.copyFileSync(src, dest); + const options = /** @type {import('./types').Options} */ (await prompts([ + { + type: 'confirm', + name: 'typescript', + message: 'Use TypeScript?', + initial: false + }, + { + type: 'confirm', + name: 'eslint', + message: 'Add ESLint for code linting?', + initial: false + }, + { + type: 'confirm', + name: 'prettier', + message: 'Add Prettier for code formatting?', + initial: false } - }); + ])); - fs.writeFileSync(path.join(target, '.gitignore'), gitignore_contents); + const name = path.basename(path.resolve(cwd)); - const name = path.basename(path.resolve(target)); + write_template_files(`default-${options.typescript ? 'ts' : 'js'}`, name, cwd); + write_common_files(cwd, options); - const pkg_file = path.join(target, 'package.json'); - const pkg_json = fs - .readFileSync(pkg_file, 'utf-8') - .replace('~TODO~', name) - .replace(/"(.+)": "workspace:.+"/g, (_m, name) => `"${name}": "next"`); // TODO ^${versions[name]} + console.log(bold(green('✔ Copied project files'))); - fs.writeFileSync(pkg_file, pkg_json); + if (options.typescript) { + console.log( + bold( + green( + '✔ Added TypeScript support. ' + + 'To use it inside Svelte components, add lang="ts" to the attributes of a script tag.' + ) + ) + ); + } - console.log(bold(green('✔ Copied project files'))); + if (options.eslint) { + console.log( + bold( + green( + '✔ Added ESLint.\n' + + 'Readme for ESLint and Svelte: https://github.com/sveltejs/eslint-plugin-svelte3' + ) + ) + ); + } - await prompt_modifications(target); + if (options.prettier) { + console.log( + bold( + green( + '✔ Added Prettier.\n' + + 'General formatting options: https://prettier.io/docs/en/options.html\n' + + 'Svelte-specific formatting options: https://github.com/sveltejs/prettier-plugin-svelte#options' + ) + ) + ); + } console.log( '\nWant to add other parts to your code base? ' + @@ -85,7 +108,7 @@ async function main() { console.log('\nNext steps:'); let i = 1; - const relative = path.relative(process.cwd(), target); + const relative = path.relative(process.cwd(), cwd); if (relative !== '') { console.log(` ${i++}: ${bold(cyan(`cd ${relative}`))}`); } @@ -98,46 +121,102 @@ async function main() { } /** - * Go through the prompts to let the user setup his project. - * - * @param {string} target + * @param {string} id + * @param {string} name + * @param {string} cwd */ -async function prompt_modifications(target) { - const ts_response = await prompts({ - type: 'confirm', - name: 'value', - message: 'Use TypeScript in components?', - initial: false - }); - await add_typescript(target, ts_response.value); - - const css_response = await prompts({ - type: 'select', - name: 'value', - message: 'What do you want to use for writing Styles in Svelte components?', - choices: [ - { title: 'CSS', value: 'css' }, - { title: 'Less', value: 'less' }, - { title: 'SCSS', value: 'scss' } - ] - }); - await add_css(target, css_response.value); +function write_template_files(id, name, cwd) { + const template = fileURLToPath(new URL(`./dist/templates/${id}.json`, import.meta.url).href); + const { files } = /** @type {import('./types').Template} */ (JSON.parse( + fs.readFileSync(template, 'utf-8') + )); - const eslint_response = await prompts({ - type: 'confirm', - name: 'value', - message: 'Add ESLint for code linting?', - initial: false + files.forEach((file) => { + const dest = path.join(cwd, file.name); + mkdirp(path.dirname(dest)); + + fs.writeFileSync( + dest, + file.encoding === 'base64' + ? Buffer.from(file.contents, 'base64') + : file.contents.replace(/~TODO~/g, name) + ); }); - await add_eslint(target, eslint_response.value, ts_response.value); +} + +/** + * + * @param {string} cwd + * @param {import('./types').Options} options + */ +function write_common_files(cwd, options) { + const shared = fileURLToPath(new URL('./dist/shared.json', import.meta.url).href); + const { files } = /** @type {import('./types').Common} */ (JSON.parse( + fs.readFileSync(shared, 'utf-8') + )); - const prettier_response = await prompts({ - type: 'confirm', - name: 'value', - message: 'Add Prettier for code formatting?', - initial: false + const pkg_file = path.join(cwd, 'package.json'); + const pkg = /** @type {any} */ (JSON.parse(fs.readFileSync(pkg_file, 'utf-8'))); + + files.forEach((file) => { + const include = file.include.every((condition) => options[condition]); + const exclude = file.exclude.some((condition) => options[condition]); + + if (exclude || !include) return; + + if (file.name === 'package.json') { + const new_pkg = JSON.parse(file.contents); + merge(pkg, new_pkg); + } else { + const dest = path.join(cwd, file.name); + mkdirp(path.dirname(dest)); + fs.writeFileSync(dest, file.contents); + } }); - await add_prettier(target, prettier_response.value, eslint_response.value); + + pkg.dependencies = sort_keys(pkg.dependencies); + pkg.devDependencies = sort_keys(pkg.devDependencies); + + fs.writeFileSync(pkg_file, JSON.stringify(pkg, null, ' ')); +} + +/** + * @param {any} target + * @param {any} source + */ +function merge(target, source) { + for (const key in source) { + if (key in target) { + const target_value = target[key]; + const source_value = source[key]; + + if ( + typeof source_value !== typeof target_value || + Array.isArray(source_value) !== Array.isArray(target_value) + ) { + throw new Error('Mismatched values'); + } + + merge(target_value, source_value); + } else { + target[key] = source[key]; + } + } +} + +/** @param {Record} obj */ +function sort_keys(obj) { + if (!obj) return; + + /** @type {Record} */ + const sorted = {}; + Object.keys(obj) + .sort() + .forEach((key) => { + sorted[key] = obj[key]; + }); + + return sorted; } main(); diff --git a/packages/create-svelte/cli/modifications/add_css.js b/packages/create-svelte/cli/modifications/add_css.js deleted file mode 100644 index 0fabe673f275..000000000000 --- a/packages/create-svelte/cli/modifications/add_css.js +++ /dev/null @@ -1,58 +0,0 @@ -import { bold, green } from 'kleur/colors'; -import { - add_svelte_preprocess_to_config, - copy_from_template_additions, - update_component, - update_package_json_dev_deps -} from './utils'; - -/** - * Add chosen CSS language to the project. - * - * @param {string} cwd - * @param {'css' | 'scss' | 'less'} which - */ -export default async function add_css(cwd, which) { - if (which === 'css') { - copy_from_template_additions(cwd, ['src', 'app.css']); - console.log('You can add support for CSS preprocessors like SCSS/Less/PostCSS later.'); - } else if (which === 'less') { - update_package_json_dev_deps(cwd, { - less: '^3.0.0', - 'svelte-preprocess': '^4.0.0' - }); - copy_from_template_additions(cwd, ['src', 'app.less']); - update_component(cwd, 'src/routes/$layout.svelte', [['../app.css', '../app.less']]); - update_component(cwd, 'src/lib/Counter.svelte', [['