├── .eslintignore ├── .eslintrc.js ├── .github ├── CONTRIBUTING.md └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── chore.md │ ├── feature_request.md │ └── question.md ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── bin └── index.js ├── docs ├── .nojekyll ├── README.md ├── index.html └── reset.css ├── example ├── package.json └── src │ ├── App.svelte │ ├── index.html │ └── index.js ├── lib ├── __tests__ │ └── inititalize.test.js ├── build.js ├── constants.js ├── development.js ├── index.js ├── initialize.js ├── modules │ └── template │ │ ├── __tests__ │ │ ├── get-template-contents.test.js │ │ ├── markup.test.js │ │ ├── read-template.test.js │ │ ├── report-template-usage.test.js │ │ └── write-template.test.js │ │ ├── compile.js │ │ ├── get-template-contents.js │ │ ├── index.js │ │ ├── markup.js │ │ ├── read-template.js │ │ ├── report-template-usage.js │ │ └── write-template.js ├── rollup.js ├── templates │ └── template.html └── utils │ ├── __tests__ │ ├── argument.test.js │ ├── get-days-in-ms.test.js │ ├── path-cwd-resolve.test.js │ └── warn.test.js │ ├── ensure-argument.js │ ├── fs.js │ ├── get-days-in-ms.js │ ├── path-cwd-resolve.js │ └── warn.js ├── package.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | docs/ 3 | node_modules/ 4 | example/ 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true 4 | }, 5 | parserOptions: { 6 | ecmaVersion: 2020, 7 | sourceType: 'module' 8 | }, 9 | extends: [ 10 | 'himynameisdave/configurations/node' 11 | ], 12 | rules: { 13 | 'no-console': 'off', 14 | 'object-property-newline': ['error', { allowAllPropertiesOnSameLine: false }], 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | Thanks for taking the time to contribute to `svb`!!! 🎉 👌 💪 4 | 5 | Feel free to [file issues](https://github.com/himynameisdave/svb/issues/new) if you encounter any bugs, or if you have a good idea for a new feature. Try to include as much information as possible, including details about what versions of Node and this package that you are using. 6 | 7 | If you're feeling more adventurous, a [pull request](https://github.com/himynameisdave/svb/compare) would be very welcomed! In lieu of a formal style, please try to maintain clean code, and include unit tests to cover any new functionality you are adding. 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: "\U0001F41B Help us squash bugs" 4 | title: '' 5 | labels: 'Status: Todo, Type: Bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Versions (please complete the following information):** 27 | - OS: [e.g. macOS 10.14.5] 28 | - `svb` Version: [eg: `0.1.0`] 29 | - NodeJS Version: [eg: `v12.5.0`] 30 | 31 | **Additional context or comments** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/chore.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Chore 3 | about: "\U0001F3D7 A chore that needs to be done" 4 | title: '' 5 | labels: 'Status: Todo, Type: Chore' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe what needs to be done** 11 | - [eg: "Fix travis.yml config"] 12 | 13 | **Are there any dependency updates?** 14 | - [eg: "Bump svelte version"] 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: "✨ Suggest new features" 4 | title: '' 5 | labels: 'Type: Feature, Status: Todo' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: "❓ Question about this project" 4 | title: '' 5 | labels: 'Status: Todo, Type: Question' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dotenv environment variables file 2 | .env 3 | 4 | # Dependency directories 5 | node_modules/ 6 | 7 | # macos annoyance 8 | *.DS_Store 9 | 10 | # Logs 11 | logs 12 | *.log 13 | npm-debug.log* 14 | yarn-debug.log* 15 | yarn-error.log* 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | 29 | # TypeScript v1 declaration files 30 | typings/ 31 | 32 | # Optional npm cache directory 33 | .npm 34 | 35 | # Optional eslint cache 36 | .eslintcache 37 | 38 | # Optional REPL history 39 | .node_repl_history 40 | 41 | # Output of 'npm pack' 42 | *.tgz 43 | 44 | # Yarn Integrity file 45 | .yarn-integrity 46 | 47 | # Hide stuff in examples 48 | example/yarn.lock 49 | example/dist/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | coverage/ 3 | docs/ 4 | example/ 5 | node_modules/ 6 | *__tests__**/* 7 | .travis.yml 8 | .eslintignore 9 | .eslintrc.js 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | - "10" 5 | - "12" 6 | after_success: 7 | - npm run coverage:report 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dave Lunny 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

svelte-bundler

3 |

📦 A zero-config CLI to bundle Svelte apps.

4 |
5 | 6 | Travis Badge 7 | 8 | 9 | Coverage Status 10 | 11 | 12 | Version 13 | 14 | 15 | Downloads 16 | 17 |
18 |
19 | 20 | --- 21 | 22 | This is a (mildly) opinionated and very lightweight Svelte compiler/bundler, which is meant to take some of the headaches out of setting up and configuring simple [Svelte](https://svelte.dev/) projects. 23 | 24 | Differs from [Sapper](https://sapper.svelte.dev), which is more of a fully baked solution which includes SSR, routing and other goodies. This is more akin to the [react-scripts](https://github.com/facebook/create-react-app/tree/master/packages/react-scripts) used in `create-react-app`, where all of the config is hidden away so that you can just focus on building cool Svelte apps. 25 | 26 | **Notice:** This is very much a work in progress right now, so [feel free to contribute](https://github.com/himynameisdave/svb/blob/master/.github/CONTRIBUTING.md)! We'd love to get some feedback and ideas! 27 | 28 | ### Installation 29 | 30 | > _**Note:** Currently requires NodeJS >= 8.16.0_ 31 | 32 | ``` 33 | yarn add -D svb 34 | 35 | npm i -D svb 36 | ``` 37 | 38 | You could also install this globally: 39 | 40 | ``` 41 | yarn global add svb 42 | 43 | npm i -g svb 44 | ``` 45 | 46 | This provides you with the global `svb` binary (as well as a `svelte-bundler` alias, in case you like typing). 47 | 48 | 49 | ### Documentation 50 | 51 | Please view [the documentation here](https://himynameisdave.github.io/svb/#/)! 52 | 53 | --- 54 | 55 | _Created by [Dave](http://himynameisdave.com) in 2019 ✌️_ 56 | -------------------------------------------------------------------------------- /bin/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('../lib')(); 4 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/himynameisdave/svb/757b85d1186de49854fd8cde17fe1cdf38bd63c1/docs/.nojekyll -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 |
2 |

svelte-bundler

3 |

📦 A zero-config CLI to bundle Svelte apps.

4 |
5 | 6 | Travis Badge 7 | 8 | 9 | Coverage Status 10 | 11 | 12 | Version 13 | 14 | 15 | Downloads 16 | 17 |
18 |
19 | 20 | --- 21 | 22 | This is a (mildly) opinionated and very lightweight Svelte compiler/bundler, which is meant to take some of the headaches out of setting up and configuring simple [Svelte](https://svelte.dev/) projects. 23 | 24 | Differs from [Sapper](https://sapper.svelte.dev), which is more of a fully baked solution which includes SSR, routing and other goodies. This is more akin to the [react-scripts](https://github.com/facebook/create-react-app/tree/master/packages/react-scripts) used in `create-react-app`, where all of the config is hidden away so that you can just focus on building cool Svelte apps. 25 | 26 | **Notice:** This is very much a work in progress right now, so [feel free to contribute](https://github.com/himynameisdave/svb/blob/master/.github/CONTRIBUTING.md)! We'd love to get some feedback and ideas! 27 | 28 | ### Features 29 | 30 | - 📄 *Zero-config*, don't ya worry, we'll take care of that. 31 | - 👀 *Watch/dev mode*, with livereloading. 32 | - 🗺 *Sourcemaps*, for easier debugging. 33 | 34 | ## Installation 35 | 36 | > _**Note:** Currently requires NodeJS >= 8.16.0_ 37 | 38 | ``` 39 | yarn add -D svb 40 | 41 | npm i -D svb 42 | ``` 43 | 44 | You could also install this globally: 45 | 46 | ``` 47 | yarn global add svb 48 | 49 | npm i -g svb 50 | ``` 51 | 52 | This provides you with the global `svb` binary (as well as a `svelte-bundler` alias, in case you like typing). 53 | 54 | ## Usage 55 | 56 | ### Building 57 | 58 | The `svb` command allows you to bundle your Svelte apps. Most likely you will have this package installed in your `devDependencies`, and then include some kind of [npm script](https://css-tricks.com/why-npm-scripts/) which uses it, like so: 59 | 60 | ```json 61 | { 62 | "build": "svb --input src/index.js --output dist/" 63 | } 64 | ``` 65 | 66 | You'd then do one of the following to compile your project: 67 | 68 | ```bash 69 | npm run build 70 | yarn run build 71 | ``` 72 | 73 | Here's an example using npx instead: 74 | 75 | ```bash 76 | npx svb -i src/index.js -o dist/ 77 | ``` 78 | 79 | ### Options 80 | 81 | ``` 82 | Options: 83 | -i, --input Index/root file to be compiled 84 | -o, --output Bundled file path/name 85 | ``` 86 | 87 | An example of what a project might look like can be [found here](https://github.com/himynameisdave/svb/tree/master/example). This is an overview: 88 | 89 | ``` 90 | my-svelte-app/ 91 | |- package.json 92 | |- dist/ 93 | # Your compiled project 94 | |- src/ 95 | |- App.svelte 96 | |- index.js 97 | |- index.html 98 | ``` 99 | 100 | ### HTML Template 101 | 102 | `svb` will by default output a standard/bare bones `index.html` file for you. If you wish, you can customize this by including an `index.html` (or `template.html`) file in the src directory of your project, next to your `--input` file. 103 | 104 | You can customize where `svb` injects the JS bundle and CSS stylesheets by using the following tags: 105 | 106 | ``` 107 | {SVB.js} 108 | {SVB.css} 109 | ``` 110 | 111 | Example: 112 | 113 | ```html 114 | 115 | 116 | 117 | My App 118 | {SVB.css} 119 | 120 | 121 | {SVB.js} 122 | 123 | 124 | ``` 125 | 126 | ## Project 127 | 128 | ### Goals 129 | 130 | Three main goals for this project: 131 | 132 | - Simplify Svelte projects; provide a solid default for building apps. 133 | - Remain lightweight; this is not [Sapper](https://sapper.svelte.dev). 134 | - Simple to use; [don't make users think](https://en.wikipedia.org/wiki/Don't_Make_Me_Think)! 135 | 136 | ### Roadmap 137 | 138 | This is a work in progress/the project is still in beta. Here's some stuff that we want to add/take care of: 139 | 140 | - [x] Handle generation of a root `index.html` file ([#13](https://github.com/himynameisdave/svb/issues/13)) 141 | - [x] Watch/dev mode ([#4](https://github.com/himynameisdave/svb/issues/4)) 142 | - [x] Sourcemaps ([#15](https://github.com/himynameisdave/svb/issues/15)) 143 | - [ ] ~Allow some more custom configuration of rollup~ This isn't aligned with the goals of this project. 144 | - [ ] _Maybe_ add some kind of `eject` command, allow users to bump out if they choose. ([#18](https://github.com/himynameisdave/svb/issues/18)) 145 | 146 | Follow this project's [progress here](https://github.com/himynameisdave/svb/projects/1?fullscreen=true)! We hope to release a v1 soon! 147 | 148 | ### Contributing 149 | 150 | We gladly welcome new issues and pull requests. Please see the [Contributing Guide](https://github.com/himynameisdave/svb/blob/master/.github/CONTRIBUTING.md) for more info! 151 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | svb - 📦 A zero-config CLI to bundle Svelte apps 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/reset.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: 'Lexend Deca', sans-serif; 3 | } 4 | 5 | html, 6 | body { 7 | background-color: #3f3f3f; 8 | } 9 | 10 | hr, 11 | .markdown-section hr { 12 | border-bottom: 1px solid #ea6f5a; 13 | } 14 | 15 | @keyframes loading-dot { 16 | 0% { 17 | opacity: .4; 18 | transform: scale(1, 1); 19 | } 20 | 21 | 50% { 22 | opacity: 1; 23 | transform: scale(1.2, 1.2); 24 | } 25 | 26 | 100% { 27 | opacity: .4; 28 | transform: scale(1, 1); 29 | } 30 | } 31 | 32 | .loading { 33 | margin: 2rem 0; 34 | text-align: center; 35 | width: 100%; 36 | } 37 | 38 | .loading__dot { 39 | animation: loading-dot 1.5s infinite ease-in-out; 40 | background-color: #ea6f5a; 41 | border-radius: 30px; 42 | display: inline-block; 43 | height: 30px; 44 | width: 30px; 45 | } 46 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "my-app", 4 | "scripts": { 5 | "build": "svb --input src/index.js --output dist/", 6 | "dev": "svb --input src/index.js --output dist/ --watch" 7 | }, 8 | "dependencies": { 9 | "svb": "*", 10 | "svelte": "*" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /example/src/App.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 32 | 33 |
34 |

Sample SVB App

35 |

Behold, the almighty counter app!

36 |

The count is currently {count}!

37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | -------------------------------------------------------------------------------- /example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | My Svelte App 7 | 8 | 9 | {SVB.css} 10 | 11 | 12 | {SVB.js} 13 | 14 | -------------------------------------------------------------------------------- /example/src/index.js: -------------------------------------------------------------------------------- 1 | import App from './App.svelte'; 2 | 3 | 4 | const app = new App({ 5 | target: document.body, 6 | }); 7 | 8 | export default app; 9 | -------------------------------------------------------------------------------- /lib/__tests__/inititalize.test.js: -------------------------------------------------------------------------------- 1 | const commander = require('commander'); 2 | const updateNotifier = require('update-notifier'); 3 | 4 | const initialize = require('../initialize.js'); 5 | 6 | 7 | jest.mock('commander'); 8 | jest.mock('update-notifier'); 9 | 10 | describe('initialize', () => { 11 | const mockNotify = jest.fn(); 12 | beforeEach(() => { 13 | updateNotifier.mockImplementation(() => ({ 14 | notify: mockNotify, 15 | })); 16 | const getOption = (parse = () => { }) => () => ({ 17 | option: getOption(), 18 | parse, 19 | }); 20 | commander.version.mockReturnValue({ 21 | option: getOption(), 22 | }); 23 | }); 24 | it('calls the update notifier', () => { 25 | initialize(); 26 | expect(mockNotify).toHaveBeenCalledTimes(1); 27 | }); 28 | // TODO [>=1]: also assert that it calls commander... 29 | }); 30 | -------------------------------------------------------------------------------- /lib/build.js: -------------------------------------------------------------------------------- 1 | const rollup = require('rollup'); 2 | 3 | const { 4 | getInputConfig, 5 | getOutputConfig, 6 | } = require('./rollup.js'); 7 | const template = require('./modules/template'); 8 | 9 | 10 | const build = async ({ 11 | input, output, isDevelopmentMode, 12 | }) => { 13 | // Handle the index.html stuff 14 | await template({ 15 | input, 16 | output, 17 | }); 18 | const bundle = await rollup.rollup( 19 | await getInputConfig({ 20 | input, 21 | output, 22 | isDevelopmentMode, 23 | }), 24 | ); 25 | return bundle.write( 26 | getOutputConfig({ 27 | input, 28 | output, 29 | isDevelopmentMode, 30 | }), 31 | ); 32 | 33 | }; 34 | 35 | module.exports = build; 36 | -------------------------------------------------------------------------------- /lib/constants.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | HTML_TEMPLATE_NAMES: ['index.html', 'template.html'], 3 | DEFAULT_TEMPLATE_PATH: '../../templates/template.html', 4 | BUNDLE_FILENAME: { 5 | CSS: 'bundle.css', 6 | JS: 'index.js', 7 | }, 8 | HTML_OUTPUT_INDEX: 'index.html', 9 | }; 10 | -------------------------------------------------------------------------------- /lib/development.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const rollup = require('rollup'); 4 | const clear = require('console-clear'); 5 | const chalk = require('chalk'); 6 | 7 | const { 8 | getInputConfig, 9 | getOutputConfig, 10 | } = require('./rollup.js'); 11 | const pathCwdResolve = require('./utils/path-cwd-resolve.js'); 12 | const template = require('./modules/template'); 13 | 14 | 15 | const logger = (string) => console.log(`\n\n${string}`); 16 | 17 | const watchHandlers = { 18 | START: () => logger(chalk.yellow('📦 Bundling your Svelte app!')), 19 | END: () => logger(chalk.green('⚡️ Bundled your Svelte app!')), 20 | ERROR: ({ error }) => logger(chalk.red(`Error: ️${error.message}!\n${error.frame}`)), 21 | }; 22 | 23 | const watch = async ({ 24 | input, 25 | output, 26 | isDevelopmentMode, 27 | }) => { 28 | const inputFolder = path.dirname(input); 29 | const config = { 30 | ...await getInputConfig({ 31 | input, 32 | output, 33 | isDevelopmentMode, 34 | }), 35 | output: getOutputConfig({ 36 | output, 37 | }), 38 | watch: { 39 | chokidar: { 40 | cwd: process.cwd(), 41 | paths: [ 42 | `${inputFolder}/**`, 43 | `${inputFolder}/*.html`, 44 | ], 45 | }, 46 | clearScreen: true, 47 | exclude: ['node_modules/**'], 48 | // paths: 49 | }, 50 | }; 51 | 52 | // Initial template build 53 | template({ 54 | input, 55 | output, 56 | }); 57 | 58 | const watcher = rollup.watch(config); 59 | watcher.on('change', (changedPath) => { 60 | /** 61 | * TODO [2019-10-01]: tech-debt This runs on every change event, which is not desirable 62 | * This is not desirable. 63 | * 64 | */ 65 | template({ 66 | input, 67 | output, 68 | }); 69 | // TODO [2019-10-10]: More logs if --debug mode? 70 | clear(true); 71 | logger(chalk.yellow(`📦 ${changedPath} changed!`)); 72 | }); 73 | 74 | }; 75 | 76 | module.exports = watch; 77 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | // Core 2 | const { mkdirp } = require('fs-extra'); 3 | 4 | const init = require('./initialize.js'); 5 | const build = require('./build.js'); 6 | const development = require('./development.js'); 7 | // Utils 8 | const ensureArg = require('./utils/ensure-argument.js'); 9 | const pathCwdResolve = require('./utils/path-cwd-resolve.js'); 10 | const warn = require('./utils/warn.js'); 11 | 12 | 13 | const main = async () => { 14 | const { 15 | input, 16 | output, 17 | watch, 18 | } = init(); 19 | const config = { 20 | input: pathCwdResolve(input), 21 | output: pathCwdResolve(output), 22 | isDevelopmentMode: !!watch, 23 | }; 24 | // Ensure the user has provided the arguments 25 | ensureArg(input, 'input'); 26 | ensureArg(output, 'output'); 27 | 28 | // Create the output directory 29 | await mkdirp(config.output); 30 | 31 | try { 32 | return config.isDevelopmentMode 33 | ? development(config) 34 | : build(config); 35 | } catch (error) { 36 | warn(error.message, error); 37 | process.exit(1); 38 | } 39 | }; 40 | 41 | module.exports = main; 42 | -------------------------------------------------------------------------------- /lib/initialize.js: -------------------------------------------------------------------------------- 1 | const commander = require('commander'); 2 | const updateNotifier = require('update-notifier'); 3 | 4 | const pkg = require('../package.json'); 5 | 6 | const getDaysInMS = require('./utils/get-days-in-ms.js'); 7 | 8 | /** 9 | * Initializes the program, by doing two things: 10 | * 1. Running updateNotifier 11 | * 2. Setting up commander and return the `program` 12 | */ 13 | const initialize = () => { 14 | // Update user if newer version exists 15 | updateNotifier({ 16 | pkg, 17 | updateCheckInterval: getDaysInMS(4), 18 | }).notify(); 19 | 20 | return ( 21 | commander 22 | .version(pkg.version, '-v, --version') 23 | .option('-i, --input ', 'Index/root file to be compiled') 24 | .option('-o, --output ', 'Bundled file path/name') 25 | .option('-w, --watch', 'Run in dev/watch mode') 26 | .parse(process.argv) 27 | ); 28 | }; 29 | 30 | module.exports = initialize; 31 | -------------------------------------------------------------------------------- /lib/modules/template/__tests__/get-template-contents.test.js: -------------------------------------------------------------------------------- 1 | const getTemplateContents = require('../get-template-contents.js'); 2 | const reportTemplateUsage = require('../report-template-usage.js'); 3 | const readTemplate = require('../read-template.js'); 4 | const { read } = require('../../../utils/fs.js'); 5 | const { HTML_TEMPLATE_NAMES } = require('../../../constants.js'); 6 | 7 | 8 | jest.mock('../../../utils/fs.js'); 9 | jest.mock('../read-template.js'); 10 | jest.mock('../report-template-usage.js'); 11 | reportTemplateUsage.mockImplementation(() => { }); 12 | jest.spyOn(console, 'log').mockImplementation(() => { }); 13 | 14 | describe('modules/template/getTemplateContents', () => { 15 | const mockTemplateContents = 'Custom Template'; 16 | describe('when a valid html template is provided', () => { 17 | const mockFileName = HTML_TEMPLATE_NAMES[0]; 18 | it('should return the contents of the template file', async () => { 19 | readTemplate.mockImplementationOnce(() => Promise.resolve({ 20 | contents: mockTemplateContents, 21 | fileName: mockFileName, 22 | })); 23 | const actual = await getTemplateContents('some/input/path/'); 24 | expect(actual).toBe(mockTemplateContents); 25 | }); 26 | }); 27 | describe('when a no valid html template is provided', () => { 28 | it('should return the contents of the default template', async () => { 29 | readTemplate.mockImplementation(() => Promise.resolve({ 30 | error: 'Ya done goofed!', 31 | })); 32 | read.mockImplementationOnce(() => Promise.resolve(mockTemplateContents)); 33 | const actual = await getTemplateContents('some/input/path/'); 34 | expect(actual).toBe(mockTemplateContents); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /lib/modules/template/__tests__/markup.test.js: -------------------------------------------------------------------------------- 1 | const { 2 | getCSS, 3 | getJS, 4 | } = require('../markup.js'); 5 | 6 | 7 | describe('modules/template/markup', () => { 8 | describe('getCSS', () => { 9 | it('should return expected CSS tag', () => { 10 | const mockFileName = 'bundle.css'; 11 | const expected = ``; 12 | expect(getCSS(mockFileName)).toBe(expected); 13 | }); 14 | }); 15 | describe('getJS', () => { 16 | it('should return expected JS `; 19 | expect(getJS(mockFileName)).toBe(expected); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /lib/modules/template/__tests__/read-template.test.js: -------------------------------------------------------------------------------- 1 | const readTemplate = require('../read-template.js'); 2 | const { read } = require('../../../utils/fs.js'); 3 | 4 | 5 | jest.mock('../../../utils/fs.js'); 6 | 7 | 8 | describe('modules/template/readTemplate', () => { 9 | const mockFilename = 'some-template.html'; 10 | it('should return an contents and fileName', async () => { 11 | const mockTemplateContents = 'template contents'; 12 | read.mockImplementationOnce(() => Promise.resolve(mockTemplateContents)); 13 | const results = await readTemplate(mockFilename); 14 | expect(results).toHaveProperty('contents', mockTemplateContents); 15 | expect(results).toHaveProperty('fileName', mockFilename); 16 | }); 17 | it('should return an error if reading template fails', async () => { 18 | const error = 'Ya done goofed!'; 19 | read.mockImplementationOnce(() => Promise.reject(new Error(error))); 20 | const results = await readTemplate(mockFilename); 21 | expect(results).toHaveProperty('error'); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /lib/modules/template/__tests__/report-template-usage.test.js: -------------------------------------------------------------------------------- 1 | const reportTemplateUsage = require('../report-template-usage.js'); 2 | 3 | 4 | describe('modules/template/reportTemplateUsage', () => { 5 | jest.spyOn(console, 'log').mockImplementation(() => { }); 6 | describe('when hasTemplate is true', () => { 7 | const hasTemplate = true; 8 | it('logs the template which we are using', () => { 9 | const mockFileName = 'template.html'; 10 | reportTemplateUsage(hasTemplate, mockFileName); 11 | expect(console.log).toHaveBeenCalledWith(`📄 Using ${mockFileName} template`); 12 | }); 13 | it('falls back to saying "Using the provided template" if no filename is provided', () => { 14 | reportTemplateUsage(hasTemplate); 15 | expect(console.log).toHaveBeenCalledWith('📄 Using the provided template'); 16 | }); 17 | }); 18 | describe('when hasTemplate is false', () => { 19 | const hasTemplate = false; 20 | it('logs that the default template is being used instead', () => { 21 | reportTemplateUsage(hasTemplate); 22 | expect(console.log).toHaveBeenCalledWith('📄 Using the default HTML template instead'); 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /lib/modules/template/__tests__/write-template.test.js: -------------------------------------------------------------------------------- 1 | const writeTemplate = require('../write-template.js'); 2 | const { write } = require('../../../utils/fs.js'); 3 | 4 | 5 | const mockBasePath = 'absolute/path/'; 6 | 7 | jest.mock('../../../utils/fs.js'); 8 | jest.mock('../../../utils/path-cwd-resolve.js', () => (path) => `${mockBasePath}${path}`); // eslint-disable-line unicorn/consistent-function-scoping 9 | 10 | 11 | describe('modules/template/writeTemplate', () => { 12 | it('calls write with the correct path & data', async () => { 13 | write.mockImplementationOnce(() => Promise.resolve()); 14 | const mockOutput = 'some/dist/path'; 15 | const mockCompiled = 'some compiled stuff'; 16 | await writeTemplate({ 17 | output: mockOutput, 18 | compiled: mockCompiled, 19 | }); 20 | expect(write).toHaveBeenCalledWith(`${mockBasePath}${mockOutput}`, mockCompiled); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /lib/modules/template/compile.js: -------------------------------------------------------------------------------- 1 | const pupa = require('pupa'); 2 | const { minify } = require('html-minifier'); 3 | 4 | // Local 5 | const { BUNDLE_FILENAME } = require('../../constants.js'); 6 | 7 | const markup = require('./markup.js'); 8 | // Constants 9 | 10 | // Options for html-minify package 11 | // https://github.com/kangax/html-minifier#options-quick-reference 12 | const MINIFY_OPTIONS = { 13 | collapseBooleanAttributes: true, 14 | collapseWhitespace: true, 15 | minifyCSS: true, 16 | minifyJS: true, 17 | removeComments: true, 18 | sortAttributes: true, 19 | sortClassName: true, 20 | useShortDoctype: true, 21 | }; 22 | 23 | /** 24 | * Responsible for compiling and minifying the template HTML 25 | * 26 | * @param {object} props 27 | * @param {object} props.title An optional title for the app 28 | * @param {string} props.template The template HTML string 29 | */ 30 | const compile = ({ 31 | title = 'My App', template, 32 | }) => { 33 | const compiledTemplate = pupa(template, { 34 | SVB: { 35 | title, 36 | css: markup.getCSS(BUNDLE_FILENAME.CSS), 37 | js: markup.getJS(BUNDLE_FILENAME.JS), 38 | }, 39 | }); 40 | return minify(compiledTemplate, MINIFY_OPTIONS); 41 | }; 42 | 43 | module.exports = compile; 44 | -------------------------------------------------------------------------------- /lib/modules/template/get-template-contents.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | // Local 4 | // Utils 5 | const { read } = require('../../utils/fs.js'); 6 | const pathCwdResolve = require('../../utils/path-cwd-resolve.js'); 7 | // Constants 8 | const { 9 | HTML_TEMPLATE_NAMES, 10 | DEFAULT_TEMPLATE_PATH, 11 | } = require('../../constants.js'); 12 | 13 | const readTemplate = require('./read-template.js'); 14 | const reportTemplateUsage = require('./report-template-usage.js'); 15 | 16 | 17 | /** 18 | * Resolves the HTML template contents, either provided by the user, 19 | * or generated based on our template. 20 | * 21 | * @param {string} inputFolder The folder path of the input JS file (from path.dirname()) 22 | */ 23 | const getTemplateContents = async (inputFolder = '') => { // TODO [>=0.5.0]: have a better/different default here 24 | const readTemplatesResults = await Promise.all( 25 | HTML_TEMPLATE_NAMES.map((templateName) => readTemplate( 26 | pathCwdResolve(inputFolder, templateName), 27 | )), 28 | ); 29 | const localTemplate = readTemplatesResults.find(template => !template.error); 30 | if (!localTemplate) { 31 | console.log(`📇 No HTML template file found in "${inputFolder}"`); 32 | reportTemplateUsage(false); // "Using the default template" 33 | const templatePath = path.resolve(__dirname, DEFAULT_TEMPLATE_PATH); 34 | return read(templatePath); 35 | } 36 | reportTemplateUsage(true, localTemplate.fileName); // Using your file 37 | return localTemplate.contents; 38 | }; 39 | 40 | module.exports = getTemplateContents; 41 | -------------------------------------------------------------------------------- /lib/modules/template/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const readPkgUp = require('read-pkg-up'); 4 | 5 | // Local 6 | const compile = require('./compile.js'); 7 | const getTemplateContents = require('./get-template-contents.js'); 8 | const writeTemplate = require('./write-template.js'); 9 | 10 | 11 | /** 12 | * Responsible for writing user-provided/generated 13 | * index HTML template to the output directory 14 | * 15 | * @param {object} param 16 | * @param {string} input The root/input file 17 | * @param {string} output The output directory 18 | */ 19 | const main = async ({ 20 | input, output, 21 | }) => { 22 | const inputFolder = path.dirname(input); 23 | // Get the title to inject into the template (if neeeded) 24 | const { 'package': { name } } = await readPkgUp(); 25 | // Get the contents, either user-provided or generated 26 | const template = await getTemplateContents(inputFolder); 27 | // Compile the template (inserting the variables) 28 | const compiled = compile({ 29 | title: name || 'My App', 30 | template, 31 | }); 32 | // Write the file to the output directory 33 | await writeTemplate({ 34 | output, 35 | compiled, 36 | }); 37 | console.log('✍️ Wrote index.html file'); 38 | }; 39 | 40 | module.exports = main; 41 | -------------------------------------------------------------------------------- /lib/modules/template/markup.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Gets the code for the CSS import 3 | * 4 | * @param {string} filename The name of the CSS file 5 | */ 6 | const getCSS = filename => ``; 7 | 8 | /** 9 | * Gets the `; 14 | 15 | const markup = { 16 | getCSS, 17 | getJS, 18 | }; 19 | 20 | module.exports = markup; 21 | -------------------------------------------------------------------------------- /lib/modules/template/read-template.js: -------------------------------------------------------------------------------- 1 | // Utils 2 | const { read } = require('../../utils/fs.js'); 3 | 4 | /** 5 | * Actually reads the contents of a given HTML template file. 6 | * Like utils.read but with different outputs 7 | * 8 | * @param {string} path Absolute path to the HTML template file 9 | */ 10 | const readTemplate = async (path) => { 11 | try { 12 | return { 13 | contents: await read(path), 14 | fileName: path.split(path.sep).pop(), 15 | }; 16 | } catch (error) { 17 | return { 18 | error, 19 | }; 20 | } 21 | }; 22 | 23 | module.exports = readTemplate; 24 | -------------------------------------------------------------------------------- /lib/modules/template/report-template-usage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Logs the template being used to the console 3 | * 4 | * @param {boolean} hasTemplate If a user-provided template was provided 5 | * @param {string} fileName Name of the user-provided file being used 6 | */ 7 | const reportTemplateUsage = (hasTemplate = false, fileName = 'the provided') => console.log( 8 | hasTemplate 9 | ? `📄 Using ${fileName} template` 10 | : '📄 Using the default HTML template instead', 11 | ); 12 | 13 | module.exports = reportTemplateUsage; 14 | -------------------------------------------------------------------------------- /lib/modules/template/write-template.js: -------------------------------------------------------------------------------- 1 | // Utils 2 | const { write } = require('../../utils/fs.js'); 3 | const pathCwdResolve = require('../../utils/path-cwd-resolve.js'); 4 | const { HTML_OUTPUT_INDEX } = require('../../constants.js'); 5 | 6 | 7 | /** 8 | * Function for writing the compiled template HTML file to disk 9 | * 10 | * @param {object} props 11 | * @param {string} props.output The output directory 12 | * @param {string} props.compiled The compiled template 13 | */ 14 | const writeTemplate = ({ 15 | output, compiled, 16 | }) => write( 17 | pathCwdResolve(output, HTML_OUTPUT_INDEX), 18 | compiled, 19 | ); 20 | 21 | module.exports = writeTemplate; 22 | -------------------------------------------------------------------------------- /lib/rollup.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const svelte = require('rollup-plugin-svelte'); 4 | const resolve = require('rollup-plugin-node-resolve'); 5 | const commonjs = require('rollup-plugin-commonjs'); 6 | const livereload = require('rollup-plugin-livereload'); 7 | const serve = require('rollup-plugin-serve'); 8 | const sourcemaps = require('rollup-plugin-sourcemaps'); 9 | const { terser } = require('rollup-plugin-terser'); 10 | const getPort = require('get-port'); 11 | 12 | const { BUNDLE_FILENAME } = require('./constants.js'); 13 | 14 | 15 | const getPlugins = async ({ 16 | input, 17 | output, 18 | isDevelopmentMode, 19 | }) => { 20 | const inputFolder = path.dirname(input); 21 | const port = await getPort({ 22 | port: getPort.makeRange(3000, 3100), 23 | }); 24 | return isDevelopmentMode 25 | // Dev plugins 26 | ? [ 27 | sourcemaps(), 28 | serve({ 29 | // Launch in browser 30 | open: true, 31 | contentBase: output, 32 | port, 33 | verbose: true, 34 | }), 35 | livereload({ 36 | watch: [ 37 | output, 38 | inputFolder, 39 | ], 40 | exts: ['html', 'svelte'], // eslint-disable-line unicorn/prevent-abbreviations 41 | }), 42 | ] 43 | // Prod plugins 44 | : [ 45 | terser(), 46 | ]; 47 | }; 48 | 49 | const getInputConfig = async ({ 50 | input, output, isDevelopmentMode, 51 | }) => ({ 52 | input, 53 | plugins: [ 54 | svelte({ 55 | // Extract any component CSS out into a separate file, as it is better for performance 56 | css: css => css.write(`${output}/${BUNDLE_FILENAME.CSS}`, isDevelopmentMode), // 2nd argument is for sourcemaps 57 | }), 58 | // For resolve external NPM dependencies 59 | resolve({ 60 | browser: true, 61 | }), 62 | // For convert any CommonJS modules to ES6 63 | commonjs({ 64 | include: 'node_modules/**', // TODO [>=1]: is this relative to svb/node_modules? 65 | }), 66 | ].concat( 67 | await getPlugins({ 68 | input, 69 | output, 70 | isDevelopmentMode, 71 | }), 72 | ), 73 | }); 74 | 75 | const getOutputConfig = ({ 76 | output, 77 | isDevelopmentMode, 78 | }) => ({ 79 | format: 'iife', 80 | dir: output, // eslint-disable-line unicorn/prevent-abbreviations 81 | name: 'bundle.js', 82 | sourcemap: isDevelopmentMode, 83 | }); 84 | 85 | module.exports.getInputConfig = getInputConfig; 86 | module.exports.getOutputConfig = getOutputConfig; 87 | -------------------------------------------------------------------------------- /lib/templates/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {SVB.title} 7 | 8 | 9 | {SVB.css} 10 | 11 | 12 | {SVB.js} 13 | 14 | -------------------------------------------------------------------------------- /lib/utils/__tests__/argument.test.js: -------------------------------------------------------------------------------- 1 | const ensureArg = require('../ensure-argument.js'); 2 | const warn = require('../warn.js'); 3 | 4 | 5 | jest.mock('../warn.js'); 6 | 7 | describe('utils/ensureArg', () => { 8 | beforeEach(() => { 9 | warn.mockImplementation(() => { }); 10 | }); 11 | 12 | describe('when the argument is invalid', () => { 13 | const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => { }); 14 | afterAll(() => { 15 | mockExit.mockClear(); 16 | warn.mockClear(); 17 | }); 18 | // Run the fn 19 | ensureArg(undefined, 'input'); 20 | it('warns with the proper warning', () => { 21 | expect(warn).toHaveBeenCalledWith( 22 | 'Please provide an input value with the --input flag!', 23 | ); 24 | expect(warn).toHaveBeenCalledTimes(1); 25 | }); 26 | it('kills the process', () => { 27 | expect(mockExit).toHaveBeenCalledWith(1); 28 | expect(mockExit).toHaveBeenCalledTimes(1); 29 | }); 30 | }); 31 | 32 | describe('when the argument is valid', () => { 33 | const mockExit = jest.spyOn(process, 'exit').mockImplementation(() => { }); 34 | // Run the fn 35 | ensureArg('some-input.js', 'input'); 36 | it('does nothing', () => { 37 | expect(warn).not.toHaveBeenCalled(); 38 | expect(mockExit).not.toHaveBeenCalled(); 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /lib/utils/__tests__/get-days-in-ms.test.js: -------------------------------------------------------------------------------- 1 | const getDaysInMS = require('../get-days-in-ms.js'); 2 | 3 | 4 | describe('utils/getDaysInMS', () => { 5 | it('returns the correct number of days in MS', () => { 6 | const expected = 172800000; // two days 7 | const actual = getDaysInMS(2); 8 | expect(actual).toBe(expected); 9 | }); 10 | it('defaults to 1 day if no day is provided', () => { 11 | const expected = 86400000; // one day 12 | const actual = getDaysInMS(); 13 | expect(actual).toBe(expected); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /lib/utils/__tests__/path-cwd-resolve.test.js: -------------------------------------------------------------------------------- 1 | const pathCwdResolve = require('../path-cwd-resolve.js'); 2 | 3 | 4 | describe('utils/pathCwdResolve', () => { 5 | const mockCwd = '/some/file/path'; 6 | beforeEach(() => { 7 | const mockProcessCwd = jest.spyOn(process, 'cwd'); 8 | mockProcessCwd.mockReturnValue(mockCwd); 9 | }); 10 | 11 | it('returns the expected path', () => { 12 | const mockAdditionalPath = 'folder/file.js'; 13 | const actual = pathCwdResolve(mockAdditionalPath); 14 | const expected = `${mockCwd}/${mockAdditionalPath}`; 15 | expect(actual).toBe(expected); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /lib/utils/__tests__/warn.test.js: -------------------------------------------------------------------------------- 1 | const warn = require('../warn.js'); 2 | 3 | 4 | describe('utils/warn', () => { 5 | beforeEach(() => { 6 | console.warn = jest.fn().mockImplementation(() => { }); 7 | }); 8 | afterAll(() => { 9 | console.warn.clearMock(); 10 | }); 11 | it('logs the provided message with a ⚠️ emoji', () => { 12 | const mockMessage = 'Hello world'; 13 | warn(mockMessage); 14 | expect(console.warn).toHaveBeenCalledWith(`⚠️ ${mockMessage}`, null); 15 | }); 16 | it('defaults to "Uh oh! Something went wrong!" when no message is provided', () => { 17 | warn(); 18 | expect(console.warn).toHaveBeenCalledWith( 19 | '⚠️ Uh oh! Something went wrong!', 20 | null, 21 | ); 22 | }); 23 | it('logs the rest of the error, if provided', () => { 24 | const mockMessage = 'Ya done goofed'; 25 | const mockError = { 26 | code: 'ENOENT', 27 | message: mockMessage, 28 | }; 29 | warn(mockMessage, mockError); 30 | expect(console.warn).toHaveBeenCalledWith(`⚠️ ${mockMessage}`, mockError); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /lib/utils/ensure-argument.js: -------------------------------------------------------------------------------- 1 | const warn = require('./warn.js'); 2 | 3 | 4 | const ERROR_EXIT_CODE = 1; 5 | 6 | /** 7 | * Verifies that the provided arguments are valid/not nullish. 8 | * Warns the user and exits with an error code if invalid. 9 | * 10 | * @param {string} arg The actual argument value 11 | * @param {string} argLabel A label for the argument (ie: what the argument is called) 12 | */ 13 | const ensureArgument = (argument, argumentLabel) => { 14 | if (!argument || argument.length === '') { 15 | warn(`Please provide an ${argumentLabel} value with the --${argumentLabel} flag!`); 16 | process.exit(ERROR_EXIT_CODE); 17 | } 18 | }; 19 | 20 | module.exports = ensureArgument; 21 | -------------------------------------------------------------------------------- /lib/utils/fs.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { promisify } = require('util'); 3 | 4 | 5 | const readFile = promisify(fs.readFile); 6 | const writeFile = promisify(fs.writeFile); 7 | 8 | module.exports = { 9 | read: path => readFile(path, 'utf8'), 10 | write: (path, data) => writeFile(path, data, 'utf8'), 11 | }; 12 | -------------------------------------------------------------------------------- /lib/utils/get-days-in-ms.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the number of ms for a given number of days 3 | * 4 | * @param {number} days The number of days in ms (defaults to 1) 5 | */ 6 | const getDaysInMS = (days = 1) => 1000 * 60 * 60 * 24 * days; 7 | 8 | module.exports = getDaysInMS; 9 | -------------------------------------------------------------------------------- /lib/utils/path-cwd-resolve.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | /** 4 | * Wrapper around path.resolve, with process.cwd() as the 1st argument 5 | * 6 | * @param {string | Array} pth The path/path pieces which you want to resolve 7 | */ 8 | const pathCwdResolve = (...pth) => path.resolve(process.cwd(), ...pth); 9 | 10 | module.exports = pathCwdResolve; 11 | -------------------------------------------------------------------------------- /lib/utils/warn.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Log a warning message to the console 3 | * 4 | * @param {string} message The message to be logged to the console 5 | */ 6 | const warn = (message = 'Uh oh! Something went wrong!', error = null) => console.warn(`⚠️ ${message}`, error); 7 | 8 | module.exports = warn; 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svb", 3 | "version": "0.4.0-beta.0", 4 | "description": "📦 A zero-config CLI to bundle Svelte apps", 5 | "main": "lib/index.js", 6 | "bin": { 7 | "svelte-bundler": "bin/index.js", 8 | "svb": "bin/index.js" 9 | }, 10 | "scripts": { 11 | "build": "rollup -c", 12 | "release": "np --no-yarn", 13 | "lint": "eslint ./ --quiet", 14 | "lint:loud": "eslint ./", 15 | "lint:fix": "eslint ./ --fix", 16 | "test": "jest", 17 | "test:watch": "jest --watch", 18 | "test:coverage": "jest --coverage", 19 | "coverage:report": "jest --coverage && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js", 20 | "coverage:view": "jest --coverage && open ./coverage/lcov-report/index.html -a \"Google Chrome\"" 21 | }, 22 | "dependencies": { 23 | "chalk": "^2.4.2", 24 | "chokidar": "^3.1.1", 25 | "commander": "^3.0.1", 26 | "console-clear": "^1.1.1", 27 | "fs-extra": "^8.1.0", 28 | "get-port": "^5.0.0", 29 | "html-minifier": "^4.0.0", 30 | "pupa": "^2.0.1", 31 | "read-pkg-up": "^6.0.0", 32 | "rollup": "^1.21.4", 33 | "rollup-plugin-commonjs": "^10.1.0", 34 | "rollup-plugin-json": "^4.0.0", 35 | "rollup-plugin-livereload": "^1.0.3", 36 | "rollup-plugin-node-resolve": "^5.2.0", 37 | "rollup-plugin-serve": "^1.0.1", 38 | "rollup-plugin-sourcemaps": "^0.4.2", 39 | "rollup-plugin-svelte": "^5.1.0", 40 | "rollup-plugin-terser": "^5.1.2", 41 | "svelte": "^3.12.1", 42 | "update-notifier": "^3.0.1" 43 | }, 44 | "devDependencies": { 45 | "coveralls": "^3.0.6", 46 | "eslint": "^6.4.0", 47 | "eslint-config-himynameisdave": "^1.0.0-beta.1", 48 | "eslint-plugin-filenames": "^1.3.2", 49 | "eslint-plugin-import": "^2.18.2", 50 | "eslint-plugin-jest": "^22.17.0", 51 | "eslint-plugin-promise": "^4.2.1", 52 | "eslint-plugin-unicorn": "^11.0.0", 53 | "jest": "^24.9.0", 54 | "np": "^5.1.0" 55 | }, 56 | "engines": { 57 | "node": ">= 8.16.0" 58 | }, 59 | "repository": { 60 | "type": "git", 61 | "url": "git+https://github.com/himynameisdave/svelte-bundler.git" 62 | }, 63 | "keywords": [ 64 | "svelte", 65 | "bundler", 66 | "compiler", 67 | "rollup", 68 | "zero-configuration", 69 | "svelte-cli" 70 | ], 71 | "author": { 72 | "name": "Dave Lunny", 73 | "email": "d@velunny.com", 74 | "url": "http://himynameisdave.com/" 75 | }, 76 | "license": "MIT", 77 | "bugs": { 78 | "url": "https://github.com/himynameisdave/svelte-bundler/issues" 79 | }, 80 | "homepage": "https://himynameisdave.github.io/svb/#/", 81 | "private": false 82 | } 83 | --------------------------------------------------------------------------------