11#!/usr/bin/env zx
2+ /* global $, fs, path, argv, echo, spinner */
23
3- $ . verbose = false
4+ const name = argv . _ [ 0 ]
5+ if ( ! name ) {
6+ echo `Error: please specify the app name`
7+ process . exit ( 1 )
8+ }
9+
10+ function p ( ...args ) {
11+ return path . join ( name , ...args )
12+ }
413
514async function patchFiles ( files , ...replacers ) {
615 for ( const file of [ files ] . flat ( ) ) {
@@ -12,9 +21,9 @@ async function patchFiles(files, ...replacers) {
1221 }
1322}
1423
15- async function patchPackage ( name , ...dependencies ) {
24+ async function patchPackage ( ...dependencies ) {
1625 const version = async ( dep ) => ( await $ `npm show ${ dep } version` ) . stdout . trim ( )
17- const file = path . join ( name , 'package.json' )
26+ const file = p ( 'package.json' )
1827 let pkg = await fs . readJson ( file )
1928 for ( const dep of dependencies ) {
2029 pkg . devDependencies [ dep . slice ( 1 ) ] =
@@ -23,31 +32,83 @@ async function patchPackage(name, ...dependencies) {
2332 await fs . writeJson ( file , pkg , { spaces : 2 } )
2433}
2534
26- const name = argv . _ [ 0 ]
27- if ( ! name ) {
28- echo `Error: please specify the app name`
29- process . exit ( 1 )
30- }
31-
3235await spinner ( 'replace favicon' , async ( ) => {
33- await fetch ( 'https://raw.githubusercontent.com/zerodevx/sveltekit-starter/main/favicon.png' ) . then (
34- ( r ) => r . body . pipe ( fs . createWriteStream ( path . join ( name , 'static' , 'favicon.png' ) ) )
35- )
36+ const req = await fetch ( 'https://cdn.jsdelivr.net/gh/zerodevx/sveltekit-starter/favicon.png' )
37+ const blob = await req . blob ( )
38+ const buf = await blob . arrayBuffer ( )
39+ await fs . writeFile ( p ( 'static' , 'favicon.png' ) , Buffer . from ( buf ) )
3640} )
3741
38- await spinner ( 'add tailwindcss' , async ( ) => {
39- await $ `cd ${ name } && npx -y svelte-add@latest tailwindcss`
40- await patchPackage ( name , '+@tailwindcss/typography' )
41- await patchFiles ( path . join ( name , 'tailwind.config.cjs' ) , [
42- `plugins: [` ,
43- `plugins: [require('@tailwindcss/typography'),`
42+ await spinner ( 'add tailwindcss, iconify and fontsource' , async ( ) => {
43+ await patchPackage (
44+ '+tailwindcss' ,
45+ '+@tailwindcss/typography' ,
46+ '+@fontsource-variable/inter' ,
47+ '+@iconify/tailwind' ,
48+ '+@iconify-json/mdi' ,
49+ '+prettier-plugin-tailwindcss'
50+ )
51+ await fs . writeFile (
52+ p ( 'tailwind.config.js' ) ,
53+ `import { addIconSelectors } from '@iconify/tailwind'
54+ import typography from '@tailwindcss/typography'
55+ import dt from 'tailwindcss/defaultTheme'
56+
57+ /** @type {import('tailwindcss').Config} */
58+ export default {
59+ content: ['./src/**/*.{html,js,svelte,ts}'],
60+ theme: {
61+ extend: {
62+ fontFamily: {
63+ sans: ['Inter Variable', ...dt.fontFamily.sans]
64+ }
65+ }
66+ },
67+ plugins: [addIconSelectors(['mdi']), typography]
68+ }`
69+ )
70+ await fs . writeFile (
71+ p ( 'postcss.config.js' ) ,
72+ `/** @type {import('postcss-load-config').Config} */
73+ export default {
74+ plugins: {
75+ tailwindcss: {},
76+ autoprefixer: {}
77+ }
78+ }`
79+ )
80+ await fs . writeFile (
81+ p ( 'src' , 'app.pcss' ) ,
82+ `/* Write your global styles here, in PostCSS syntax */
83+ @tailwind base;
84+ @tailwind components;
85+ @tailwind utilities;`
86+ )
87+ await fs . writeFile (
88+ p ( 'src' , 'routes' , '+layout.svelte' ) ,
89+ `<script>
90+ import '@fontsource-variable/inter'
91+ import '../app.pcss'
92+ </script>
93+
94+ <slot />`
95+ )
96+ await patchFiles ( p ( 'src' , 'routes' , '+page.svelte' ) , [
97+ `</h1>` ,
98+ `</h1>\n<span class="iconify mdi--heart text-red-600 animate-pulse" />\n`
4499 ] )
100+ await patchFiles (
101+ p ( 'svelte.config.js' ) ,
102+ [ `import` , `import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';\nimport` ] ,
103+ [ `\n};` , `, preprocess: [vitePreprocess()]\n};` ]
104+ )
45105} )
46106
47107await spinner ( 'patch prettier' , async ( ) => {
48- const file = path . join ( name , '.prettierrc' )
49- await fs . writeJson ( file , {
50- ...( await fs . readJson ( file ) ) ,
108+ let config = await fs . readJson ( p ( '.prettierrc' ) )
109+ config . plugins = [ ...config . plugins , 'prettier-plugin-tailwindcss' ]
110+ await fs . writeJson ( p ( '.prettierrc' ) , {
111+ ...config ,
51112 printWidth : 100 ,
52113 useTabs : false ,
53114 semi : false ,
@@ -60,24 +121,21 @@ await spinner('patch prettier', async () => {
60121} )
61122
62123await spinner ( 'patch eslint' , async ( ) => {
63- await patchFiles ( path . join ( name , '.eslintrc.cjs ') , [
64- `}\n}; ` ,
65- `},\n\trules : { 'no-tabs': 'error', 'no-unexpected-multiline': 'error' }\n}; `
124+ await patchFiles ( p ( 'eslint.config.js ') , [
125+ `languageOptions ` ,
126+ `rules : { 'no-tabs': 'error', 'no-unexpected-multiline': 'error' }, languageOptions `
66127 ] )
67128} )
68129
69130await spinner ( 'add adapter-static' , async ( ) => {
70- await patchFiles ( path . join ( name , 'svelte.config.js' ) , [ `adapter-auto` , `adapter-static` ] )
131+ await patchFiles ( p ( 'svelte.config.js' ) , [ `adapter-auto` , `adapter-static` ] )
71132 await patchPackage ( name , '-@sveltejs/adapter-auto' , '+@sveltejs/adapter-static' )
72- await fs . outputFile (
73- path . join ( name , 'src' , 'routes' , '+layout.js' ) ,
74- `export const prerender = true\n`
75- )
133+ await fs . writeFile ( p ( 'src' , 'routes' , '+layout.js' ) , `export const prerender = true\n` )
76134} )
77135
78136await spinner ( 'add versioning' , async ( ) => {
79137 await patchFiles (
80- path . join ( name , 'svelte.config.js' ) ,
138+ p ( 'svelte.config.js' ) ,
81139 [
82140 `static';` ,
83141 `static';\nimport { readFileSync } from 'node:fs'\n\nconst { version: name } = JSON.parse(readFileSync(new URL('package.json', import.meta.url), 'utf8'))\n`
@@ -86,32 +144,6 @@ await spinner('add versioning', async () => {
86144 )
87145} )
88146
89- await spinner ( 'add fontsource' , async ( ) => {
90- await patchPackage ( name , '+@fontsource-variable/inter' )
91- await patchFiles ( path . join ( name , 'src' , 'routes' , '+layout.svelte' ) , [
92- `<script>` ,
93- `<script>import '@fontsource-variable/inter';`
94- ] )
95- await patchFiles (
96- path . join ( name , 'tailwind.config.cjs' ) ,
97- [ `/**` , `const dt = require('tailwindcss/defaultTheme');\n\n/**` ] ,
98- [ `extend: {}` , `extend: { fontFamily: { sans: ['Inter Variable', ...dt.fontFamily.sans] } }` ]
99- )
100- } )
101-
102- await spinner ( 'add iconify' , async ( ) => {
103- await patchPackage ( name , '+@iconify/tailwind' , '+@iconify-json/mdi' )
104- await patchFiles (
105- path . join ( name , 'tailwind.config.cjs' ) ,
106- [ `const dt` , `const { addDynamicIconSelectors } = require('@iconify/tailwind');\nconst dt` ] ,
107- [ `plugins: [` , `plugins: [addDynamicIconSelectors({ scale: 0 }),` ]
108- )
109- await patchFiles ( path . join ( name , 'src' , 'routes' , '+page.svelte' ) , [
110- `</h1>` ,
111- `</h1>\n<span class="icon-[mdi--heart] w-8 h-8 text-red-600 animate-pulse" />\n`
112- ] )
113- } )
114-
115147echo `
116148All done! Complete the setup with:
117149
0 commit comments