├── .gitignore ├── box-img-lg.png ├── box-img-sm.png ├── config └── rollup.config.js ├── contracts ├── Migrations.sol └── SimpleStorage.sol ├── migrations ├── 1_initial_migration.js └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── public ├── bundle.css ├── bundle.css.map ├── bundle.js ├── bundle.js.map └── index.html ├── readme.md ├── rollup.config.js ├── scripts └── watch.js ├── src ├── components │ ├── App.svelte │ └── Information.svelte ├── main.js └── utils │ └── web3.js ├── test ├── TestSimpleStorage.sol └── simplestorage.spec.js ├── truffle-box.json └── truffle-config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | dist 4 | .cache -------------------------------------------------------------------------------- /box-img-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antony/svelte-box/acc32b348065ab5f9baf2fd520a552bfc753072d/box-img-lg.png -------------------------------------------------------------------------------- /box-img-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antony/svelte-box/acc32b348065ab5f9baf2fd520a552bfc753072d/box-img-sm.png -------------------------------------------------------------------------------- /config/rollup.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const svelte = require('rollup-plugin-svelte') 4 | const babel = require('rollup-plugin-babel') 5 | const json = require('rollup-plugin-json') 6 | const resolve = require('rollup-plugin-node-resolve') 7 | const commonjs = require('rollup-plugin-commonjs') 8 | const copy = require('rollup-plugin-copy') 9 | const css = require('rollup-plugin-postcss') 10 | const serve = require('rollup-plugin-serve') 11 | const liveReload = require('rollup-plugin-livereload') 12 | const builtins = require('rollup-plugin-node-builtins') 13 | const globals = require('rollup-plugin-node-globals') 14 | 15 | const watch = process.env.WATCH 16 | 17 | const plugins = [ 18 | copy({ 19 | 'src/index.html': 'build/index.html', 20 | // 'node_modules/web3/dist/web3.min.js': 'build/js/web3.min.js' 21 | }), 22 | css(), 23 | json(), 24 | commonjs({ 25 | ignore: [ 'crypto', 'xmlhttprequest', 'xhr2' ] 26 | }), 27 | builtins(), 28 | globals(), 29 | resolve(), 30 | svelte({ 31 | include: 'src/components/**/*.html' 32 | }), 33 | babel({ 34 | exclude: 'node_modules/**' 35 | }) 36 | ] 37 | 38 | function getDevPlugins () { 39 | return [ 40 | serve('build'), 41 | liveReload({ 42 | watch: 'build' 43 | }) 44 | ] 45 | } 46 | 47 | module.exports = [ 48 | { 49 | input: 'src/main.js', 50 | output: { 51 | file: 'build/js/dapp.js', 52 | format: 'iife' 53 | }, 54 | plugins: watch ? plugins.concat(getDevPlugins()) : plugins, 55 | external: ['web3'] 56 | } 57 | ] 58 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } -------------------------------------------------------------------------------- /contracts/SimpleStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract SimpleStorage { 4 | event StorageSet(string _message); 5 | 6 | uint public storedData; 7 | 8 | function set(uint x) public { 9 | storedData = x; 10 | 11 | emit StorageSet("Data stored successfully!"); 12 | } 13 | 14 | function get() view public returns (uint retVal) { 15 | return storedData; 16 | } 17 | } -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("./Migrations.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | var SimpleStorage = artifacts.require("./SimpleStorage.sol"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(SimpleStorage); 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-box", 3 | "version": "2.0.0", 4 | "description": "", 5 | "main": "truffle.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "build": "rollup -c", 11 | "autobuild": "rollup -c -w", 12 | "dev": "run-p start:dev autobuild", 13 | "start": "sirv public --single", 14 | "start:dev": "sirv public --single --dev", 15 | "clean": "rm -rf ./dist ./build ./public/bundle.*", 16 | "compile": "truffle compile", 17 | "deploy": "truffle deploy", 18 | "test": "npm run test:unit && npm run test:contract", 19 | "test:unit": "mocha", 20 | "test:contract": "truffle test" 21 | }, 22 | "author": "Antony Jones", 23 | "license": "MIT", 24 | "peerDependencies": { 25 | "truffle": "3.x" 26 | }, 27 | "devDependencies": { 28 | "@beyonk/async-script-loader": "^1.0.3", 29 | "browserslist": "^4.6.6", 30 | "caniuse-lite": "^1.0.30000989", 31 | "copy-webpack-plugin": "^5.0.4", 32 | "mocha": "^5.2.0", 33 | "npm-run-all": "^4.1.5", 34 | "rollup": "^1.19.4", 35 | "rollup-plugin-commonjs": "^10.0.2", 36 | "rollup-plugin-json": "^4.0.0", 37 | "rollup-plugin-livereload": "^1.0.1", 38 | "rollup-plugin-node-builtins": "^2.1.2", 39 | "rollup-plugin-node-globals": "^1.4.0", 40 | "rollup-plugin-node-resolve": "^5.2.0", 41 | "rollup-plugin-postcss": "^2.0.3", 42 | "rollup-plugin-svelte": "^5.1.0", 43 | "rollup-plugin-terser": "^5.1.1", 44 | "shoelace-css": "^1.0.0-beta24", 45 | "svelte": "^3.8.1", 46 | "truffle-contract": "^4.0.29" 47 | }, 48 | "dependencies": { 49 | "sirv-cli": "^0.4.4" 50 | }, 51 | "svelte": { 52 | "compilerOptions": { 53 | "css": true 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /public/bundle.css: -------------------------------------------------------------------------------- 1 | .masthead.svelte-hqbxra{margin-top:3em} 2 | 3 | /*# sourceMappingURL=bundle.css.map */ -------------------------------------------------------------------------------- /public/bundle.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "file": "bundle.css", 4 | "sources": [ 5 | "../src/components/App.svelte" 6 | ], 7 | "sourcesContent": [ 8 | "
\n
\n
\n

Truffle Box

\n

Skeleton SvelteJS truffle box

\n \n \n \n
\n

Smart Contract Example

\n

If your contracts compiled and migrated successfully, below will show a stored value of 5 (by default).

\n

Try changing the value stored on line 71 of src/components/App.html.

\n

The stored value is: {storageValue}

\n
\n
\n
\n
\n\n\n\n" 9 | ], 10 | "names": [], 11 | "mappings": "AAmBE,SAAS,cAAC,CAAC,AACT,UAAU,CAAE,GAAG,AACjB,CAAC" 12 | } -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | svelte-box truffle base 8 | 9 | 10 | 11 | 14 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![box-img-lg-template](https://user-images.githubusercontent.com/218949/63261050-6ce11600-c27a-11e9-9355-1ee226b4497c.png) 2 | 3 | ## SvelteJS Truffle Box 4 | 5 | A Truffle box using [SvelteJS](https://svelte.technology/) and [Rollup](https://rollupjs.org/). 6 | 7 | This box contains everything you need to start building a smart-contract app. 8 | 9 | ### Project Goal 10 | 11 | To provide the simplest, cleanest seed for building an Ethereum dapp using [Truffle](http://truffleframework.com/), with the minimum possible dependencies, meaning that beginners and pros a like have the most transparent possible method for developing [Ethereum](https://www.ethereum.org/) contracts. 12 | 13 | ### Truffle Box 14 | 15 | A [truffle box](http://truffleframework.com/boxes/) is a seed project for building a truffle dapp. 16 | 17 | ### Why Svelte? 18 | 19 | [Svelte](https://svelte.technology) was chosen as it is a rich, state-model based, ES6, component framework with very few dependencies, which is nothing more than html, javascript, and css. Once compiled via svelte, there are no clientside dependencies at all - simply vanilla JS. 20 | 21 | [Svelte](https://svelte.technology) is basically a simple DSL (domain specific language) for building a reactive, stateful, dependency-free web-application in pure javascript. 22 | 23 | Additionally, the [Svelte](https://svelte.technology) API is so simple and well-designed, you can learn the whole thing from scratch in less than an hour! 24 | 25 | ### Why Rollup? 26 | 27 | Originally this project used ParcelJS but sadly Parcel's support for Svelte is currently broken, and has been for a while. I've switched to RollupJS in order to upgrade to Svelte 3. 28 | 29 | Currently, we load web3 from UNPKG, since it appears to be borderline impossible to bundle successfully. If anybody wants to open a PR to bundle Web3, it would be greatly appreciated. 30 | 31 | ## Setting up 32 | 33 | 1. Install truffle and an ethereum client. For local development, try Ethereum TestRPC. 34 | ```javascript 35 | npm install -g truffle // Version 3.0.5+ required. 36 | npm install -g ganache-cli // Or the ganache GUI will work too. 37 | ``` 38 | 39 | 2. Download box. 40 | ```javascript 41 | truffle unbox antony/svelte-box 42 | ``` 43 | 44 | 4. Run an Ethereum RPC. For simplicity and development we will be using Ethereum TestRPC. 45 | ```javascript 46 | ganache-cli 47 | ``` 48 | 49 | 7. Compile and migrate the contracts after authenticating your account on the blockchain (i.e. restoring from seed in MetaMask). 50 | ```javascript 51 | truffle compile 52 | truffle migrate 53 | ``` 54 | 55 | You're ready to go! 56 | 57 | ## Usage 58 | 59 | Components are in `src/components/*.html`. Everything else is in the usual place [according to the docs](https://github.com/trufflesuite/truffle-init-default) 60 | 61 | Run the testrpc so that you have a blockchain to work with, and deploy your contracts: 62 | 63 | ```bash 64 | testrpc 65 | truffle deploy 66 | ``` 67 | 68 | Log in to metamask by importing the HD Wallet that testrpc gave you, and do the same for one of the accounts by entering its private key. Then, run the dev task to have the code updated in realtime as you develop: 69 | 70 | ```bash 71 | truffle compile 72 | npm run dev 73 | ``` 74 | 75 | ## Publishing 76 | 77 | To produce your production dApp, run the build task: 78 | 79 | ```bash 80 | npm run build 81 | ``` 82 | 83 | This will publish your completed dApp to the folder `./dist` 84 | 85 | ## Testing 86 | 87 | Testing works much the same way as it does in any web-application, with an additional `truffle test` command for testing smart contracts. 88 | 89 | Be sure you've compiled your contracts before running the tests, or you'll get file not found errors. 90 | 91 | ```javascript 92 | npm run test:unit // for dApp tests 93 | npm run test:contract // for contract tests 94 | ``` 95 | 96 | ## Releasing 97 | 98 | To build the application for production, use the build command. A production build will be in the `./dist` folder. 99 | 100 | ```javascript 101 | npm run build 102 | ``` 103 | 104 | ## FAQ 105 | 106 | * __Why is there both a truffle.js file and a truffle-config.js file?__ 107 | 108 | Truffle requires the truffle.js file be named truffle-config on Windows machines. Feel free to delete the file that doesn't correspond to your platform. 109 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import svelte from 'rollup-plugin-svelte' 2 | import resolve from 'rollup-plugin-node-resolve' 3 | import commonjs from 'rollup-plugin-commonjs' 4 | import livereload from 'rollup-plugin-livereload' 5 | import { terser } from 'rollup-plugin-terser' 6 | import json from 'rollup-plugin-json' 7 | import postcss from 'rollup-plugin-postcss' 8 | import builtins from 'rollup-plugin-node-builtins' 9 | import globals from 'rollup-plugin-node-globals' 10 | 11 | const production = !process.env.ROLLUP_WATCH; 12 | 13 | export default { 14 | input: 'src/main.js', 15 | output: { 16 | sourcemap: true, 17 | format: 'iife', 18 | name: 'app', 19 | file: 'public/bundle.js' 20 | }, 21 | plugins: [ 22 | json(), 23 | postcss(), 24 | resolve({ 25 | jsnext: true, 26 | main: true, 27 | browser: true, 28 | preferBuiltins: true, 29 | dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/') 30 | }), 31 | commonjs({ 32 | }), 33 | svelte({ 34 | dev: !production, 35 | css: css => { 36 | css.write('public/bundle.css') 37 | } 38 | }), 39 | builtins(), 40 | globals(), 41 | !production && livereload('public'), 42 | production && terser() 43 | ], 44 | watch: { 45 | clearScreen: false 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /scripts/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const rollup = require('rollup') 4 | const config = require('../config/rollup.config') 5 | const ora = require('ora') 6 | 7 | const watcher = rollup.watch(config) 8 | 9 | const spinners = { } 10 | 11 | function compilationStart () { 12 | spinners.compilation = ora('Starting compilation').start() 13 | } 14 | 15 | function bundleStart () { 16 | spinners.bundle = ora('Compiling bundle').start() 17 | } 18 | 19 | function fatal (e) { 20 | spinners.bundle.fail() 21 | spinners.compilation.fail(`Compilation failed ${e.error.message}`) 22 | } 23 | 24 | function error (e) { 25 | spinners.bundle.warn(`Bundle compilation failed ${e.error.message}`) 26 | } 27 | 28 | function bundleEnd () { 29 | spinners.bundle.succeed('Bundle compilation finished') 30 | } 31 | 32 | function compilationEnd () { 33 | spinners.compilation.succeed('Compilation finished') 34 | } 35 | 36 | const eventMappings = { 37 | START: compilationStart, 38 | BUNDLE_START: bundleStart, 39 | FATAL: fatal, 40 | ERROR: error, 41 | BUNDLE_END: bundleEnd, 42 | END: compilationEnd 43 | } 44 | 45 | watcher.on('event', event => { 46 | const handler = eventMappings[event.code] 47 | return handler ? handler(event) : console.info(event) 48 | }) -------------------------------------------------------------------------------- /src/components/App.svelte: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

Truffle Box

5 |

Skeleton SvelteJS truffle box

6 | 7 | 8 | 9 |
10 |

Smart Contract Example

11 |

If your contracts compiled and migrated successfully, below will show a stored value of 5 (by default).

12 |

Try changing the value stored on line 71 of src/components/App.html.

13 |

The stored value is: {storageValue}

14 |
15 |
16 |
17 |
18 | 19 | 24 | 25 | -------------------------------------------------------------------------------- /src/components/Information.svelte: -------------------------------------------------------------------------------- 1 | {#if connected} 2 |
3 |

Good to Go!

4 |

Your Truffle Box is installed and ready.

5 |
6 | {:else} 7 |
8 |

Not connected

9 |

Could not connect to the blockchain!

10 |

Check that:

11 | 15 |
16 | {/if} 17 | 18 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | 2 | import App from './components/App.svelte' 3 | 4 | const app = new App({ 5 | target: document.body, 6 | props: {} 7 | }) 8 | 9 | export default app 10 | -------------------------------------------------------------------------------- /src/utils/web3.js: -------------------------------------------------------------------------------- 1 | import loader from '@beyonk/async-script-loader' 2 | 3 | const url = '//unpkg.com/web3@1.2.1/src/index.js' 4 | 5 | function test () { 6 | return !!window.web3 7 | } 8 | 9 | export default async function () { 10 | return new Promise((resolve) => { 11 | function init () { 12 | let web3 = window.web3 13 | 14 | if (typeof web3 !== 'undefined') { 15 | console.warn( 16 | 'Using web3 detected from external source.' + 17 | ' If using MetaMask, see the following link.' + 18 | ' Feel free to delete this warning. :)' + 19 | ' http://truffleframework.com/tutorials/truffle-and-metamask' 20 | ) 21 | 22 | resolve(new Web3(web3.currentProvider)) 23 | } else { 24 | console.warn( 25 | 'No web3 detected. Falling back to http://127.0.0.1:8545.' + 26 | ' You should remove this fallback when you deploy live, as it\'s inherently insecure.' + 27 | ' Consider switching to Metamask for development.' + 28 | ' More info here: http://truffleframework.com/tutorials/truffle-and-metamask' 29 | ) 30 | resolve(new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:8545'))) 31 | } 32 | } 33 | 34 | loader(url, test, init, { async: true, defer: true }) 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /test/TestSimpleStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.2; 2 | 3 | import "truffle/Assert.sol"; 4 | import "truffle/DeployedAddresses.sol"; 5 | import "../contracts/SimpleStorage.sol"; 6 | 7 | contract TestSimpleStorage { 8 | 9 | function testItStoresAValue() { 10 | SimpleStorage simpleStorage = SimpleStorage(DeployedAddresses.SimpleStorage()); 11 | 12 | simpleStorage.set(89); 13 | 14 | uint expected = 89; 15 | 16 | Assert.equal(simpleStorage.get(), expected, "It should store the value 89."); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /test/simplestorage.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const SimpleStorage = artifacts.require("./SimpleStorage.sol") 4 | 5 | contract('SimpleStorage', function(accounts) { 6 | let instance 7 | 8 | before(async () => { 9 | instance = await SimpleStorage.deployed() 10 | }) 11 | 12 | it('stores given value', async () => { 13 | await instance.set(89, { 14 | from: accounts[0] 15 | }) 16 | 17 | const data = await instance.get.call() 18 | assert.equal(data, 89, "The value 89 was not stored.") 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /truffle-box.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": [ 3 | "README.md", 4 | ".gitignore" 5 | ], 6 | "commands": { 7 | "compile": "truffle compile", 8 | "migrate": "truffle migrate", 9 | "deploy": "truffle deploy", 10 | "test": "truffle test && npm test", 11 | "test:contracts": "truffle test", 12 | "test:app": "npm test", 13 | "run:watch": "npm run watch", 14 | "package": "npm run build" 15 | }, 16 | "hooks": { 17 | "post-unpack": "npm install" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | networks: { 3 | development: { 4 | host: "localhost", 5 | port: 8545, 6 | network_id: "*", // Match any network id 7 | } 8 | } 9 | } --------------------------------------------------------------------------------