├── .gitignore ├── README.md ├── package.json ├── public ├── favicon.png └── index.html ├── scripts └── setupTypeScript.js ├── src ├── App.svelte ├── global.css └── main.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | public/build/bundle.* 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # svelte app 2 | 3 | This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template-webpack. 4 | 5 | To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit): 6 | 7 | ```bash 8 | npx degit sveltejs/template-webpack svelte-app 9 | cd svelte-app 10 | ``` 11 | 12 | *Note that you will need to have [Node.js](https://nodejs.org) installed.* 13 | 14 | 15 | ## Get started 16 | 17 | Install the dependencies... 18 | 19 | ```bash 20 | cd svelte-app 21 | npm install 22 | ``` 23 | 24 | ...then start webpack: 25 | 26 | ```bash 27 | npm run dev 28 | ``` 29 | 30 | Navigate to [localhost:8080](http://localhost:8080). You should see your app running. Edit a component file in `src`, save it, and the page should reload with your changes. 31 | 32 | 33 | ## Deploying to the web 34 | 35 | ### With [now](https://zeit.co/now) 36 | 37 | Install `now` if you haven't already: 38 | 39 | ```bash 40 | npm install -g now 41 | ``` 42 | 43 | Then, from within your project folder: 44 | 45 | ```bash 46 | now 47 | ``` 48 | 49 | As an alternative, use the [Now desktop client](https://zeit.co/download) and simply drag the unzipped project folder to the taskbar icon. 50 | 51 | ### With [surge](https://surge.sh/) 52 | 53 | Install `surge` if you haven't already: 54 | 55 | ```bash 56 | npm install -g surge 57 | ``` 58 | 59 | Then, from within your project folder: 60 | 61 | ```bash 62 | npm run build 63 | surge public 64 | ``` 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-app", 3 | "version": "1.0.0", 4 | "devDependencies": { 5 | "cross-env": "^7.0.3", 6 | "css-loader": "^6.7.1", 7 | "mini-css-extract-plugin": "^2.6.0", 8 | "svelte": "^4.0.0", 9 | "svelte-loader": "^3.1.9", 10 | "webpack": "^5.70.0", 11 | "webpack-cli": "^5.1.4", 12 | "webpack-dev-server": "^4.15.1" 13 | }, 14 | "scripts": { 15 | "build": "cross-env NODE_ENV=production webpack", 16 | "dev": "webpack serve" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sveltejs/template-webpack/f83daa41487188fba2ae35a94d030a0fd1e8d316/public/favicon.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Svelte app 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /scripts/setupTypeScript.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Run this script to convert the project to TypeScript. This is only guaranteed to work 3 | * on the unmodified default template; if you have done code changes you are likely need 4 | * to touch up the generated project manually. 5 | */ 6 | 7 | // @ts-check 8 | const fs = require("fs") 9 | const path = require("path") 10 | const { argv } = require("process") 11 | 12 | const projectRoot = argv[2] || path.join(__dirname, "..") 13 | 14 | function warn(message) { 15 | console.warn('Warning: ' + message); 16 | } 17 | 18 | function createFile(fileName, contents) { 19 | if (fs.existsSync(fileName)) { 20 | warn(`Wanted to create ${fileName}, but it already existed. Leaving existing file.`); 21 | } else { 22 | fs.writeFileSync(fileName, contents); 23 | } 24 | } 25 | 26 | 27 | function replaceInFile(fileName, replacements) { 28 | if (fs.existsSync(fileName)) { 29 | let contents = fs.readFileSync(fileName, 'utf8'); 30 | let hadUpdates = false; 31 | 32 | replacements.forEach(([from, to]) => { 33 | const newContents = contents.replace(from, to); 34 | 35 | const isAlreadyApplied = typeof to !== 'string' || contents.includes(to); 36 | 37 | if (newContents !== contents) { 38 | contents = newContents; 39 | hadUpdates = true; 40 | } else if (!isAlreadyApplied) { 41 | warn(`Wanted to update "${from}" in ${fileName}, but did not find it.`); 42 | } 43 | }); 44 | 45 | if (hadUpdates) { 46 | fs.writeFileSync(fileName, contents); 47 | } else { 48 | console.log(`${fileName} had already been updated.`); 49 | } 50 | } else { 51 | warn(`Wanted to update ${fileName} but the file did not exist.`); 52 | } 53 | } 54 | 55 | // Add deps to pkg.json 56 | function addDepsToPackageJson() { 57 | const pkgJSONPath = path.join(projectRoot, 'package.json'); 58 | const packageJSON = JSON.parse(fs.readFileSync(pkgJSONPath, 'utf8')); 59 | packageJSON.devDependencies = Object.assign(packageJSON.devDependencies, { 60 | 'ts-loader': '^9.0.0', 61 | '@tsconfig/svelte': '^4.0.0', 62 | '@types/node': '^16.0.0', 63 | 'svelte-check': '^3.4.4', 64 | 'svelte-preprocess': '^5.0.4', 65 | tslib: '^2.5.0', 66 | typescript: '^5.0.0' 67 | }); 68 | 69 | // Add script for checking 70 | packageJSON.scripts = Object.assign(packageJSON.scripts, { 71 | validate: 'svelte-check' 72 | }); 73 | 74 | // Write the package JSON 75 | fs.writeFileSync(pkgJSONPath, JSON.stringify(packageJSON, null, ' ')); 76 | } 77 | 78 | // mv src/main.js to main.ts - note, we need to edit rollup.config.js for this too 79 | function changeJsExtensionToTs(dir) { 80 | const elements = fs.readdirSync(dir, { withFileTypes: true }); 81 | 82 | for (let i = 0; i < elements.length; i++) { 83 | if (elements[i].isDirectory()) { 84 | changeJsExtensionToTs(path.join(dir, elements[i].name)); 85 | } else if (elements[i].name.match(/^[^_]((?!json).)*js$/)) { 86 | fs.renameSync(path.join(dir, elements[i].name), path.join(dir, elements[i].name).replace('.js', '.ts')); 87 | } 88 | } 89 | } 90 | 91 | function updateSingleSvelteFile({ view, vars, contextModule }) { 92 | replaceInFile(path.join(projectRoot, 'src', `${view}.svelte`), [ 93 | [/(?:/gm, (m, attrs) => ``], 94 | ...(vars ? vars.map(({ name, type }) => [`export let ${name};`, `export let ${name}: ${type};`]) : []), 95 | ...(contextModule ? contextModule.map(({ js, ts }) => [js, ts]) : []) 96 | ]); 97 | } 98 | 99 | // Switch the App.svelte file to use TS 100 | function updateSvelteFiles() { 101 | [ 102 | { 103 | view: 'App', 104 | vars: [{ name: 'name', type: 'string' }] 105 | }, 106 | ].forEach(updateSingleSvelteFile); 107 | } 108 | 109 | function updateWebpackConfig() { 110 | // Edit webpack config 111 | replaceInFile(path.join(projectRoot, 'webpack.config.js'), [ 112 | // Edit imports 113 | [ 114 | /require\('path'\);\r?\n(?!const sveltePreprocess)/, 115 | `require('path');\nconst sveltePreprocess = require('svelte-preprocess');\n` 116 | ], 117 | // Edit extensions 118 | [ 119 | /'\.js',/, 120 | `'.js', '.ts',` 121 | ], 122 | // Edit name of entry point 123 | [ 124 | /'\.\/src\/main.js'/, 125 | `'./src/main.ts'` 126 | ], 127 | // Add preprocess to the svelte loader, this is tricky because there's no easy signifier. 128 | // Instead we look for 'hotReload: 'prod,' 129 | [ 130 | /hotReload: \!prod(?!,\r?\n\s*preprocess)/g, 131 | 'hotReload: !prod,\n\t\t\t\t\t\tpreprocess: sveltePreprocess({ sourceMap: !prod })' 132 | ], 133 | // Add ts-loader 134 | [ 135 | /module: {\r?\n\s*rules: \[\r?\n\s*(?!{\r?\n\s*test: \/\\\.ts\$\/)/g, 136 | `module: {\n\t\trules: [\n\t\t\t{\n\t\t\t\ttest: /\\.ts$/,\n\t\t\t\tloader: 'ts-loader',\n\t\t\t\texclude: /node_modules/\n\t\t\t},\n\t\t\t`, 137 | ] 138 | ]); 139 | } 140 | 141 | // Add TSConfig 142 | function createTsConfig() { 143 | const tsconfig = `{ 144 | "extends": "@tsconfig/svelte/tsconfig.json", 145 | "include": ["src/**/*", "src/node_modules/**/*"], 146 | "exclude": ["node_modules/*", "__sapper__/*", "static/*"] 147 | }`; 148 | 149 | createFile(path.join(projectRoot, 'tsconfig.json'), tsconfig); 150 | } 151 | 152 | // Add ambient file so webpack/VS Code can pick up the Svelte ambient types 153 | function createSvelteAmbientFile() { 154 | const file = '/// \n'; 155 | createFile(path.join(projectRoot, 'src', 'global.d.ts'), file); 156 | } 157 | 158 | // Adds the extension recommendation 159 | function configureVsCode() { 160 | const dir = path.join(projectRoot, '.vscode'); 161 | 162 | if (!fs.existsSync(dir)) { 163 | fs.mkdirSync(dir); 164 | } 165 | 166 | createFile(path.join(projectRoot, '.vscode', 'extensions.json'), `{"recommendations": ["svelte.svelte-vscode"]}`); 167 | } 168 | 169 | function deleteThisScript() { 170 | fs.unlinkSync(path.join(__filename)); 171 | 172 | // Check for Mac's DS_store file, and if it's the only one left remove it 173 | const remainingFiles = fs.readdirSync(path.join(__dirname)); 174 | if (remainingFiles.length === 1 && remainingFiles[0] === '.DS_store') { 175 | fs.unlinkSync(path.join(__dirname, '.DS_store')); 176 | } 177 | 178 | // Check if the scripts folder is empty 179 | if (fs.readdirSync(path.join(__dirname)).length === 0) { 180 | // Remove the scripts folder 181 | try { 182 | fs.rmdirSync(path.join(__dirname)); 183 | } catch (e) { 184 | warn(`Cannot delete locked directory ${__dirname}`); 185 | } 186 | } 187 | } 188 | 189 | console.log(`Adding TypeScript...`); 190 | 191 | addDepsToPackageJson(); 192 | 193 | changeJsExtensionToTs(path.join(projectRoot, 'src')); 194 | 195 | updateSvelteFiles(); 196 | 197 | updateWebpackConfig(); 198 | 199 | createTsConfig(); 200 | 201 | createSvelteAmbientFile(); 202 | 203 | configureVsCode(); 204 | 205 | // Delete this script, but not during testing 206 | if (!argv[2]) { 207 | deleteThisScript(); 208 | } 209 | 210 | console.log('Converted to TypeScript.'); 211 | 212 | if (fs.existsSync(path.join(projectRoot, 'node_modules'))) { 213 | console.log(` 214 | Next: 215 | 1. run 'npm install' again to install TypeScript dependencies 216 | `); 217 | } 218 | -------------------------------------------------------------------------------- /src/App.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |

Hello {name}!

7 |

Visit the Svelte tutorial to learn how to build Svelte apps.

8 |
9 | 10 | 31 | -------------------------------------------------------------------------------- /src/global.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | } 6 | 7 | body { 8 | color: #333; 9 | margin: 0; 10 | padding: 8px; 11 | box-sizing: border-box; 12 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 13 | } 14 | 15 | a { 16 | color: rgb(0,100,200); 17 | text-decoration: none; 18 | } 19 | 20 | a:hover { 21 | text-decoration: underline; 22 | } 23 | 24 | a:visited { 25 | color: rgb(0,80,160); 26 | } 27 | 28 | label { 29 | display: block; 30 | } 31 | 32 | input, button, select, textarea { 33 | font-family: inherit; 34 | font-size: inherit; 35 | -webkit-padding: 0.4em 0; 36 | padding: 0.4em; 37 | margin: 0 0 0.5em 0; 38 | box-sizing: border-box; 39 | border: 1px solid #ccc; 40 | border-radius: 2px; 41 | } 42 | 43 | input:disabled { 44 | color: #ccc; 45 | } 46 | 47 | button { 48 | color: #333; 49 | background-color: #f4f4f4; 50 | outline: none; 51 | } 52 | 53 | button:disabled { 54 | color: #999; 55 | } 56 | 57 | button:not(:disabled):active { 58 | background-color: #ddd; 59 | } 60 | 61 | button:focus { 62 | border-color: #666; 63 | } 64 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import './global.css'; 2 | 3 | import App from './App.svelte'; 4 | 5 | const app = new App({ 6 | target: document.body, 7 | props: { 8 | name: 'world' 9 | } 10 | }); 11 | 12 | export default app; 13 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 2 | const path = require('path'); 3 | 4 | const mode = process.env.NODE_ENV || 'development'; 5 | const prod = mode === 'production'; 6 | 7 | module.exports = { 8 | entry: { 9 | 'build/bundle': ['./src/main.js'] 10 | }, 11 | resolve: { 12 | alias: { 13 | svelte: path.resolve('node_modules', 'svelte/src/runtime') 14 | }, 15 | extensions: ['.mjs', '.js', '.svelte'], 16 | mainFields: ['svelte', 'browser', 'module', 'main'], 17 | conditionNames: ['svelte', 'browser'] 18 | }, 19 | output: { 20 | path: path.join(__dirname, '/public'), 21 | filename: '[name].js', 22 | chunkFilename: '[name].[id].js' 23 | }, 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.svelte$/, 28 | use: { 29 | loader: 'svelte-loader', 30 | options: { 31 | compilerOptions: { 32 | dev: !prod 33 | }, 34 | emitCss: prod, 35 | hotReload: !prod 36 | } 37 | } 38 | }, 39 | { 40 | test: /\.css$/, 41 | use: [ 42 | MiniCssExtractPlugin.loader, 43 | 'css-loader' 44 | ] 45 | } 46 | ] 47 | }, 48 | mode, 49 | plugins: [ 50 | new MiniCssExtractPlugin({ 51 | filename: '[name].css' 52 | }) 53 | ], 54 | devtool: prod ? false : 'source-map', 55 | devServer: { 56 | hot: true, 57 | static: { 58 | directory: path.join(__dirname, 'public'), 59 | } 60 | } 61 | }; 62 | --------------------------------------------------------------------------------