├── .github └── FUNDING.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── examples ├── basic │ ├── .gitignore │ ├── README.md │ ├── package.json │ └── src │ │ └── index.js ├── with-custom-babel-config │ ├── .babelrc │ ├── .gitignore │ ├── README.md │ ├── package.json │ └── src │ │ └── index.js ├── with-custom-webpack-config │ ├── .gitignore │ ├── README.md │ ├── backpack.config.js │ ├── package.json │ └── services │ │ └── main.js ├── with-flowtype │ ├── .babelrc │ ├── .flowconfig │ ├── .gitignore │ ├── README.md │ ├── package.json │ └── src │ │ └── index.js ├── with-jest │ ├── .babelrc │ ├── .gitignore │ ├── README.md │ ├── __tests__ │ │ └── createServer.test.js │ ├── package.json │ └── src │ │ ├── createServer.js │ │ └── index.js └── with-typescript │ ├── .gitignore │ ├── README.md │ ├── backpack.config.js │ ├── package.json │ ├── src │ └── main.ts │ └── tsconfig.json ├── lerna.json ├── package.json ├── packages ├── babel-preset-backpack │ ├── README.md │ ├── index.js │ └── package.json └── backpack-core │ ├── .gitignore │ ├── README.md │ ├── babel.js │ ├── bin │ ├── backpack │ ├── build │ └── dev │ ├── config │ ├── paths.js │ └── webpack.config.js │ └── package.json └── yarn.lock /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [jaredpalmer] 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/osx,git,node,linux,macos,windows,intellij,visualstudiocode 3 | 4 | ### Git ### 5 | *.orig 6 | 7 | ### Intellij ### 8 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 9 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 10 | 11 | # User-specific stuff: 12 | .idea/**/workspace.xml 13 | .idea/**/tasks.xml 14 | .idea/dictionaries 15 | 16 | # Sensitive or high-churn files: 17 | .idea/**/dataSources/ 18 | .idea/**/dataSources.ids 19 | .idea/**/dataSources.xml 20 | .idea/**/dataSources.local.xml 21 | .idea/**/sqlDataSources.xml 22 | .idea/**/dynamic.xml 23 | .idea/**/uiDesigner.xml 24 | 25 | # Gradle: 26 | .idea/**/gradle.xml 27 | .idea/**/libraries 28 | 29 | # CMake 30 | cmake-build-debug/ 31 | 32 | # Mongo Explorer plugin: 33 | .idea/**/mongoSettings.xml 34 | 35 | ## File-based project format: 36 | *.iws 37 | 38 | ## Plugin-specific files: 39 | 40 | # IntelliJ 41 | /out/ 42 | 43 | # mpeltonen/sbt-idea plugin 44 | .idea_modules/ 45 | 46 | # JIRA plugin 47 | atlassian-ide-plugin.xml 48 | 49 | # Cursive Clojure plugin 50 | .idea/replstate.xml 51 | 52 | # Ruby plugin and RubyMine 53 | /.rakeTasks 54 | 55 | # Crashlytics plugin (for Android Studio and IntelliJ) 56 | com_crashlytics_export_strings.xml 57 | crashlytics.properties 58 | crashlytics-build.properties 59 | fabric.properties 60 | 61 | ### Intellij Patch ### 62 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 63 | 64 | # *.iml 65 | # modules.xml 66 | # .idea/misc.xml 67 | # *.ipr 68 | 69 | # Sonarlint plugin 70 | .idea/sonarlint 71 | 72 | ### Linux ### 73 | *~ 74 | 75 | # temporary files which can be created if a process still has a handle open of a deleted file 76 | .fuse_hidden* 77 | 78 | # KDE directory preferences 79 | .directory 80 | 81 | # Linux trash folder which might appear on any partition or disk 82 | .Trash-* 83 | 84 | # .nfs files are created when an open file is removed but is still being accessed 85 | .nfs* 86 | 87 | ### macOS ### 88 | *.DS_Store 89 | .AppleDouble 90 | .LSOverride 91 | 92 | # Icon must end with two \r 93 | Icon 94 | 95 | # Thumbnails 96 | ._* 97 | 98 | # Files that might appear in the root of a volume 99 | .DocumentRevisions-V100 100 | .fseventsd 101 | .Spotlight-V100 102 | .TemporaryItems 103 | .Trashes 104 | .VolumeIcon.icns 105 | .com.apple.timemachine.donotpresent 106 | 107 | # Directories potentially created on remote AFP share 108 | .AppleDB 109 | .AppleDesktop 110 | Network Trash Folder 111 | Temporary Items 112 | .apdisk 113 | 114 | ### Node ### 115 | # Logs 116 | logs 117 | *.log 118 | npm-debug.log* 119 | yarn-debug.log* 120 | yarn-error.log* 121 | 122 | # Runtime data 123 | pids 124 | *.pid 125 | *.seed 126 | *.pid.lock 127 | 128 | # Directory for instrumented libs generated by jscoverage/JSCover 129 | lib-cov 130 | 131 | # Coverage directory used by tools like istanbul 132 | coverage 133 | 134 | # nyc test coverage 135 | .nyc_output 136 | 137 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 138 | .grunt 139 | 140 | # Bower dependency directory (https://bower.io/) 141 | bower_components 142 | 143 | # node-waf configuration 144 | .lock-wscript 145 | 146 | # Compiled binary addons (http://nodejs.org/api/addons.html) 147 | build/Release 148 | 149 | # Dependency directories 150 | node_modules/ 151 | jspm_packages/ 152 | 153 | # Typescript v1 declaration files 154 | typings/ 155 | 156 | # Optional npm cache directory 157 | .npm 158 | 159 | # Optional eslint cache 160 | .eslintcache 161 | 162 | # Optional REPL history 163 | .node_repl_history 164 | 165 | # Output of 'npm pack' 166 | *.tgz 167 | 168 | # Yarn Integrity file 169 | .yarn-integrity 170 | 171 | # dotenv environment variables file 172 | .env 173 | 174 | 175 | ### OSX ### 176 | 177 | # Icon must end with two \r 178 | 179 | # Thumbnails 180 | 181 | # Files that might appear in the root of a volume 182 | 183 | # Directories potentially created on remote AFP share 184 | 185 | ### VisualStudioCode ### 186 | .vscode/* 187 | !.vscode/settings.json 188 | !.vscode/tasks.json 189 | !.vscode/launch.json 190 | !.vscode/extensions.json 191 | .history 192 | 193 | ### Windows ### 194 | # Windows thumbnail cache files 195 | Thumbs.db 196 | ehthumbs.db 197 | ehthumbs_vista.db 198 | 199 | # Folder config file 200 | Desktop.ini 201 | 202 | # Recycle Bin used on file shares 203 | $RECYCLE.BIN/ 204 | 205 | # Windows Installer files 206 | *.cab 207 | *.msi 208 | *.msm 209 | *.msp 210 | 211 | # Windows shortcuts 212 | *.lnk 213 | 214 | 215 | # End of https://www.gitignore.io/api/osx,git,node,linux,macos,windows,intellij,visualstudiocode -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | 4 | 5 | 6 | 7 | **Table of Contents** 8 | 9 | * [Contributor Covenant Code of Conduct](#contributor-covenant-code-of-conduct) 10 | * [Our Pledge](#our-pledge) 11 | * [Our Standards](#our-standards) 12 | * [Our Responsibilities](#our-responsibilities) 13 | * [Scope](#scope) 14 | * [Enforcement](#enforcement) 15 | * [Attribution](#attribution) 16 | 17 | 18 | 19 | ## Our Pledge 20 | 21 | In the interest of fostering an open and welcoming environment, we as 22 | contributors and maintainers pledge to making participation in our project and 23 | our community a harassment-free experience for everyone, regardless of age, body 24 | size, disability, ethnicity, gender identity and expression, level of experience, 25 | nationality, personal appearance, race, religion, or sexual identity and 26 | orientation. 27 | 28 | ## Our Standards 29 | 30 | Examples of behavior that contributes to creating a positive environment 31 | include: 32 | 33 | * Using welcoming and inclusive language 34 | * Being respectful of differing viewpoints and experiences 35 | * Gracefully accepting constructive criticism 36 | * Focusing on what is best for the community 37 | * Showing empathy towards other community members 38 | 39 | Examples of unacceptable behavior by participants include: 40 | 41 | * The use of sexualized language or imagery and unwelcome sexual attention or 42 | advances 43 | * Trolling, insulting/derogatory comments, and personal or political attacks 44 | * Public or private harassment 45 | * Publishing others' private information, such as a physical or electronic 46 | address, without explicit permission 47 | * Other conduct which could reasonably be considered inappropriate in a 48 | professional setting 49 | 50 | ## Our Responsibilities 51 | 52 | Project maintainers are responsible for clarifying the standards of acceptable 53 | behavior and are expected to take appropriate and fair corrective action in 54 | response to any instances of unacceptable behavior. 55 | 56 | Project maintainers have the right and responsibility to remove, edit, or 57 | reject comments, commits, code, wiki edits, issues, and other contributions 58 | that are not aligned to this Code of Conduct, or to ban temporarily or 59 | permanently any contributor for other behaviors that they deem inappropriate, 60 | threatening, offensive, or harmful. 61 | 62 | ## Scope 63 | 64 | This Code of Conduct applies both within project spaces and in public spaces 65 | when an individual is representing the project or its community. Examples of 66 | representing a project or community include using an official project e-mail 67 | address, posting via an official social media account, or acting as an appointed 68 | representative at an online or offline event. Representation of a project may be 69 | further defined and clarified by project maintainers. 70 | 71 | ## Enforcement 72 | 73 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 74 | reported by contacting the project team at [info@palmer.net](mailto:info@palmer.net). All 75 | complaints will be reviewed and investigated and will result in a response that 76 | is deemed necessary and appropriate to the circumstances. The project team is 77 | obligated to maintain confidentiality with regard to the reporter of an incident. 78 | Further details of specific enforcement policies may be posted separately. 79 | 80 | Project maintainers who do not follow or enforce the Code of Conduct in good 81 | faith may face temporary or permanent repercussions as determined by other 82 | members of the project's leadership. 83 | 84 | ## Attribution 85 | 86 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 87 | available at [http://contributor-covenant.org/version/1/4][version] 88 | 89 | [homepage]: http://contributor-covenant.org 90 | [version]: http://contributor-covenant.org/version/1/4/ 91 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute to Backpack 2 | 3 | 4 | 5 | 6 | 7 | **Table of Contents** 8 | 9 | * [How to Contribute to Backpack](#how-to-contribute-to-backpack) 10 | * [Getting started](#getting-started) 11 | * [Using Lerna](#using-lerna) 12 | * [Support](#support) 13 | 14 | 15 | 16 | ## Getting started 17 | 18 | First fork the project to your GitHub account. Then clone it, checkout a new branch, and install the dependencies. 19 | 20 | ```bash 21 | git clone https://github.com/YOUR_USERNAME/backpack.git 22 | cd backpack 23 | git checkout -B YOUR_BRANCH_NAME 24 | npm install 25 | ``` 26 | 27 | Backpack is a monorepo powered by [Lerna](https://lernajs.io/). After you install, Lerna will run its `bootstrap` command that will install all dependencies in each of the `packages` and `examples` folders, build each example, and symlink all interdependencies. 28 | 29 | Now you can run all of the examples with your **local** version of Backpack. When you make edits to anything in `packages`, you (will probably) need to restart the example you are working with to pick up changes. Imagine the following workflow: 30 | 31 | In one terminal tab, I open and run the `basic` example: 32 | 33 | ``` 34 | cd examples/basic 35 | npm run dev 36 | ``` 37 | 38 | Next, I open up `packages/backpack-core/webpack.config.js` in my editor and make some changes to the webpack configuration focusing on development mode. 39 | 40 | To try out these local changes, I would need to: 41 | 42 | * Kill the running example (i.e. `CMD + c`) 43 | * Rerun it to pickup changes (i.e. `npm run dev`) 44 | 45 | That's it. 46 | 47 | ## Using Lerna 48 | 49 | When moving between branches, it's a good idea to work with a fresh install. 50 | 51 | In your project's root run the following: 52 | 53 | ```bash 54 | ./node_modules/bin/lerna clean 55 | ./node_modules/bin/lerna bootstrap 56 | ``` 57 | 58 | This will clean out, reinstall, rebuild, and symlink all of the `examples` and `packages` properly. 59 | 60 | ## Support 61 | 62 | * Join the #backpack channel in our public Slack group. Sign up at [https://palmer.chat](https://palmer.chat/) 63 | * File an issue on GitHub 64 | * Tweet to or DM [@jaredpalmer](https://twitter.com/jaredpalmer) 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 The Palmer Group https://palmer.net 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 | ![backpack](https://cloud.githubusercontent.com/assets/4060187/21872211/318795e8-d835-11e6-8376-bea370605361.png) 2 | 3 | ![backpack-status](https://david-dm.org/palmerhq/backpack.svg?path=packages/backpack-core) 4 | [![npm version](https://badge.fury.io/js/backpack-core.svg)](https://badge.fury.io/js/backpack-core) [![Discord](https://img.shields.io/discord/769256827007139912?label=%F0%9F%92%AC%20%20join%20us%20on%20discord&style=plastic)](https://discord.com/invite/RevdZTYMzr) 5 | 6 | Backpack is minimalistic build system for Node.js. Inspired by Facebook's [create-react-app](https://github.com/facebookincubator/create-react-app), Zeit's [Next.js](https://github.com/zeit/next.js), and Remy's [Nodemon](https://github.com/remy/nodemon), Backpack lets you create modern Node.js apps and services with zero configuration. Backpack handles all the file-watching, live-reloading, transpiling, and bundling, so you don't have to. It comes with a few ~~conventions~~ defaults (like support for the latest JavaScript awesomeness (i.e. async/await, object rest spread, and class properties)), but everything can be customized to fit your project's needs. Best of all, you can easily add Backpack to your existing Node.js project with just a single dependency. 7 | 8 | **Backpack comes with the "battery-pack included":** 9 | 10 | * Latest ES6 features (including module syntax, async/await, object rest spread) 11 | * SUPER friendly, human readable error messages 12 | * Live reload (on saves, add/delete file, etc.) 13 | * Zero-config, one dependency. 14 | 15 | HOWEVER, you can configure Backpack to your project's needs by extending [the underlying Webpack 4 configuration](#custom-configuration). 16 | 17 | **PLEASE READ:** If you're thinking of using Backpack with React.js, you should use [Razzle](https://github.com/jaredpalmer/razzle) instead. It is a project purpose-built for SSR React with an almost identical API. 18 | 19 | 20 | 21 | 22 | 23 | **Table of Contents** 24 | 25 | * [How to use](#how-to-use) 26 | * [Custom configuration](#custom-configuration) 27 | * [Customizing webpack config](#customizing-webpack-config) 28 | * [Customizing babel config](#customizing-babel-config) 29 | * [Building for Production](#building-for-production) 30 | * [CLI Commands](#cli-commands) 31 | * [`backpack dev`](#backpack-dev) 32 | * [`backpack build`](#backpack-build) 33 | * [FAQ](#faq) 34 | * [Inspiration](#inspiration) 35 | * [Authors](#authors) 36 | 37 | 38 | 39 | ## How to use 40 | 41 | Install it: 42 | 43 | ```bash 44 | npm i backpack-core --save 45 | ``` 46 | 47 | and add a script to your package.json like this: 48 | 49 | ```json 50 | { 51 | "scripts": { 52 | "dev": "backpack" 53 | } 54 | } 55 | ``` 56 | 57 | After that there are just a few ~~conventions~~ defaults: 58 | 59 | * `src/index.js`: the entry of your app. 60 | 61 | ...actually that's it. 62 | 63 | You can then run your application in development mode: 64 | 65 | ```bash 66 | npm run dev 67 | ``` 68 | 69 | Successful builds will show a console like this. _Note: screenshot taken from running the [basic example](https://github.com/palmerhq/backpack/tree/master/examples/basic)_ 70 | npm run dev 71 | 72 | ### Custom configuration 73 | 74 | For custom advanced behavior, you can create a `backpack.config.js` in the root of your project's directory (next to `package.json`). 75 | 76 | ```js 77 | // backpack.config.js 78 | // IMPORTANT: This file is not going through babel transformation. 79 | // You can however use the ES2015 features supported by your Node.js version. 80 | module.exports = { 81 | /* config options here */ 82 | }; 83 | ``` 84 | 85 | ### Customizing webpack config 86 | 87 | [Example](https://github.com/palmerhq/backpack/tree/master/examples/with-custom-webpack-config) 88 | 89 | To extend webpack, you can define a function that extends its config via `backpack.config.js`. 90 | 91 | ```js 92 | // backpack.config.js 93 | module.exports = { 94 | webpack: (config, options, webpack) => { 95 | // Perform customizations to config 96 | // Important: return the modified config 97 | return config; 98 | }, 99 | }; 100 | ``` 101 | 102 | ### Customizing babel config 103 | 104 | [Example](https://github.com/palmerhq/backpack/tree/master/examples/with-custom-babel-config) 105 | 106 | To extend our usage of `babel`, you can define a `.babelrc` file at the root of your app. This file is optional. 107 | 108 | If found, Backpack will consider it to be the _source of truth_. Thus it must define what Backpack needs as well, which is the `backpack-core/babel` preset. 109 | 110 | This is designed so that you are not surprised by modifications we could make to the default `babel` configurations. 111 | 112 | Here's an example `.babelrc` file: 113 | 114 | ```js 115 | { 116 | "presets": [ 117 | "backpack-core/babel", 118 | "stage-0" 119 | ] 120 | } 121 | ``` 122 | 123 | _Note: This works [exactly like Next.js does](https://github.com/zeit/next.js#customizing-babel-config)._ 124 | 125 | ### Building for Production 126 | 127 | Add a npm script for the build step: 128 | 129 | ```json 130 | { 131 | "scripts": { 132 | "dev": "backpack", 133 | "build": "backpack build" 134 | } 135 | } 136 | ``` 137 | 138 | Then run the build command and start your app 139 | 140 | ```bash 141 | npm run build 142 | node ./build/main.js 143 | ``` 144 | 145 | ## CLI Commands 146 | 147 | ### `backpack dev` 148 | 149 | Runs backpack in development mode. 150 | 151 | Your code will reload if you make edits. 152 | You will see the build errors in the console that look like this. 153 | 154 | backpack dev 155 | 156 | ### `backpack build` 157 | 158 | Builds the app for production to the `build` folder. 159 | It correctly bundles your production mode and optimizes the build for the best performance. 160 | 161 | You can run your production application with the following command: 162 | 163 | ```bash 164 | node ./build/main.js 165 | ``` 166 | 167 | Your application is ready to be deployed! 168 | 169 | _Note: Make sure to add the `build` directory to your `.gitignore` to keep compiled code out of your git repository_ 170 | 171 | ## FAQ 172 | 173 |
174 | Is this like Create-React-App or Next.js? 175 | 176 | Yes and No. 177 | 178 | Yes in that they will all make your life easier. 179 | 180 | No in that it that Backpack is focused on server-only applications. You should use create-react-app or Next.js for your frontend and then build your backend with Backpack. 181 | 182 |
183 | 184 |
185 | Can I use this with React to build a universal app? 186 | 187 | Technically, yes. However, we strongly advise against it at the moment. Backpack handles file-watching and reloading in a way that will make things like webpack-hot-middleware annoying to work with. 188 |
189 | 190 |
191 | What syntactic features are transpiled? How do I change them? 192 | 193 | We track V8. Since V8 has wide support for ES6, we don't transpile it. Since V8 doesn’t support async/await and class properties yet, we transpile those. 194 | 195 | See [this](https://github.com/palmerhq/backpack/blob/master/packages/backpack-core/config/webpack.config.js#L83) and [this](https://github.com/palmerhq/backpack#customizing-webpack) 196 |
197 | 198 |
199 | Why is it called Backpack? 200 | 201 | Backpack is focused on server-only applications. We've been using it for building out Node.js backends and microservices. Under the hood, Webpack and a few other tools make the magic happen. Hence Backend + Webpack = *Backpack*. 202 |
203 | 204 | ## Inspiration 205 | 206 | * [jlongster/backend-with-webpack](https://github.com/jlongster/backend-with-webpack) 207 | * [nyt/kyt](https://github.com/NYTimes/kyt) 208 | * [zeit/next.js](https://github.com/zeit/next.js) 209 | * [facebookincubator/create-react-app](https://github.com/facebookincubator/create-react-app) 210 | 211 | ## Authors 212 | 213 | * Jared Palmer ([@jaredpalmer](https://twitter.com/jaredpalmer)) - The Palmer Group 214 | -------------------------------------------------------------------------------- /examples/basic/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /examples/basic/README.md: -------------------------------------------------------------------------------- 1 | # Basic Example 2 | 3 | ## How to use 4 | 5 | Download the example [or clone the whole project](https://github.com/palmerhq/backpack.git): 6 | 7 | ```bash 8 | curl https://codeload.github.com/palmerhq/backpack/tar.gz/master | tar -xz --strip=2 backpack-master/examples/basic 9 | cd basic 10 | ``` 11 | 12 | Install it and run: 13 | 14 | ```bash 15 | npm install 16 | npm run dev 17 | ``` 18 | 19 | ## Idea behind the example 20 | 21 | This is a basic example of how to use Backpack in a project. It is a simple Express.js server. It demonstrates how easy it is to use 22 | Backpack in a project. It also shows off some of the default syntax features provided by Backpack such as async/await and object rest spread 23 | as well as a Webpack environment flag (`__DEV__`). 24 | -------------------------------------------------------------------------------- /examples/basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backpack-examples-basic", 3 | "version": "0.8.4", 4 | "scripts": { 5 | "start": "node ./build/main.js", 6 | "dev": "backpack dev", 7 | "build": "backpack build", 8 | "postinstall": "backpack build" 9 | }, 10 | "license": "MIT", 11 | "dependencies": { 12 | "backpack-core": "^0.8.4", 13 | "express": "^4.16.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/basic/src/index.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | 3 | const app = express(); 4 | 5 | app.get('/', async (req, res) => { 6 | const thing = await Promise.resolve({ one: 'two' }) // async/await! 7 | .catch(e => res.json({ error: e.message })); 8 | return res.json({ ...thing, hello: 'world' }); // object-rest-spread! 9 | }); 10 | 11 | const port = process.env.PORT || 3000; 12 | 13 | app.listen(port, err => { 14 | if (err) { 15 | console.error(err); 16 | } 17 | 18 | if (__DEV__) { 19 | // webpack flags! 20 | console.log('> in development'); 21 | } 22 | 23 | console.log(`> listening on port ${port}`); 24 | }); 25 | -------------------------------------------------------------------------------- /examples/with-custom-babel-config/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "backpack-core/babel" 4 | 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-proposal-do-expressions" 8 | ] 9 | } -------------------------------------------------------------------------------- /examples/with-custom-babel-config/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /examples/with-custom-babel-config/README.md: -------------------------------------------------------------------------------- 1 | # Custom Babel Configuration Example 2 | 3 | ## How to use 4 | 5 | Download the example [or clone the whole project](https://github.com/palmerhq/backpack.git): 6 | 7 | ```bash 8 | curl https://codeload.github.com/palmerhq/backpack/tar.gz/master | tar -xz --strip=2 backpack-master/examples/with-custom-babel-config 9 | cd with-custom-babel-config 10 | ``` 11 | 12 | Install it and run: 13 | 14 | ```bash 15 | npm install 16 | npm run dev 17 | ``` 18 | 19 | ## Idea behind the example 20 | 21 | This demonstrates how extend the default Backpack babel configuration with a custom `.babelrc` file. 22 | More specifically, this example shows how to add all `stage-0` transformations through `babel-preset-stage-0`. 23 | 24 | Be sure to include `backpack-core/babel` in your `.babelrc` as the first item in the presets array: 25 | 26 | ```json 27 | { 28 | "presets": ["backpack-core/babel", "..."] 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /examples/with-custom-babel-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backpack-examples-with-custom-babel-config", 3 | "version": "0.8.4", 4 | "scripts": { 5 | "start": "node ./build/main.js", 6 | "dev": "backpack dev", 7 | "build": "backpack build", 8 | "postinstall": "backpack build" 9 | }, 10 | "license": "MIT", 11 | "dependencies": { 12 | "@babel/core": "^7.0.0", 13 | "@babel/plugin-proposal-do-expressions": "^7.0.0", 14 | "backpack-core": "^0.8.4", 15 | "express": "^4.14.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/with-custom-babel-config/src/index.js: -------------------------------------------------------------------------------- 1 | const randomNo = Math.ceil(Math.random() * 100) 2 | 3 | // `do` expressions are a new syntax proposal. 4 | // @see: https://babeljs.io/docs/plugins/transform-do-expressions/ 5 | const message = do { 6 | if (randomNo < 30) { 7 | 'Do not give up. Try again.' 8 | } else if (randomNo < 60) { 9 | 'You are a lucky guy' 10 | } else { 11 | 'You are soooo lucky!' 12 | } 13 | } 14 | 15 | console.log(`number: ${randomNo}`) 16 | console.log(`message: ${message}`) 17 | -------------------------------------------------------------------------------- /examples/with-custom-webpack-config/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /examples/with-custom-webpack-config/README.md: -------------------------------------------------------------------------------- 1 | # Custom Webpack Configuration Example 2 | 3 | ## How to use 4 | 5 | Download the example [or clone the whole project](https://github.com/palmerhq/backpack.git): 6 | 7 | ```bash 8 | curl https://codeload.github.com/palmerhq/backpack/tar.gz/master | tar -xz --strip=2 backpack-master/examples/with-custom-webpack-config 9 | cd with-custom-webpack-config 10 | ``` 11 | 12 | Install it and run: 13 | 14 | ```bash 15 | npm install 16 | npm run dev 17 | ``` 18 | 19 | ## Idea behind the example 20 | 21 | This demonstrates how to customize the underlying Webpack 2 configuration in a Backpack project using a `backpack.config.js` file. 22 | The app itself is exactly the same simple Express.js server in the basic example. However, the entry point to the application has been 23 | changed from `./src/index.js` to `./services/main.js`. 24 | -------------------------------------------------------------------------------- /examples/with-custom-webpack-config/backpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | webpack: (config, options, webpack) => { 3 | // Perform customizations to config 4 | // Important: return the modified config 5 | 6 | // changes the name of the entry point from index -> main.js 7 | config.entry.main = [ 8 | './services/main.js' 9 | ] 10 | 11 | return config 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/with-custom-webpack-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backpack-examples-with-custom-webpack-config", 3 | "version": "0.8.4", 4 | "scripts": { 5 | "start": "node ./build/main.js", 6 | "dev": "backpack dev", 7 | "build": "backpack build", 8 | "postinstall": "backpack build" 9 | }, 10 | "license": "MIT", 11 | "dependencies": { 12 | "backpack-core": "^0.8.4", 13 | "express": "^4.14.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/with-custom-webpack-config/services/main.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | 3 | const app = express(); 4 | 5 | app.get('/', async (req, res) => { 6 | const thing = await Promise.resolve({ one: 'two' }) // async/await! 7 | .catch(e => res.json({ error: e.message })); 8 | return res.json({ ...thing, hello: 'world' }); // object-rest-spread! 9 | }); 10 | 11 | const port = process.env.PORT || 3000; 12 | 13 | app.listen(port, err => { 14 | if (err) { 15 | console.error(err); 16 | } 17 | 18 | if (__DEV__) { 19 | // webpack flags! 20 | console.log('> in development'); 21 | } 22 | 23 | console.log(`> listening on port ${port}`); 24 | }); 25 | -------------------------------------------------------------------------------- /examples/with-flowtype/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "backpack-core/babel" 4 | ], 5 | "plugins": [ 6 | "@babel/plugin-transform-flow-strip-types" 7 | ] 8 | } -------------------------------------------------------------------------------- /examples/with-flowtype/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/invariant/.* 3 | 4 | [include] 5 | 6 | [libs] 7 | 8 | [options] 9 | -------------------------------------------------------------------------------- /examples/with-flowtype/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /examples/with-flowtype/README.md: -------------------------------------------------------------------------------- 1 | # FlowType Example 2 | 3 | ## How to use 4 | 5 | Download the example [or clone the whole project](https://github.com/palmerhq/backpack.git): 6 | 7 | ```bash 8 | curl https://codeload.github.com/palmerhq/backpack/tar.gz/master | tar -xz --strip=2 backpack-master/examples/with-flowtype 9 | cd with-flowtype 10 | ``` 11 | 12 | Install it and run: 13 | 14 | ```bash 15 | npm install 16 | npm run dev 17 | ``` 18 | 19 | ## Idea behind the example 20 | 21 | This demonstrates how to add [Flow](https://flowtype.org/) to your Backpack project. Flow is a static type checker that helps you write code 22 | with fewer bugs. Check out this [introduction to using static types in JavaScript](https://medium.com/@preethikasireddy/why-use-static-types-in-javascript-part-1-8382da1e0adb) if you are new to this concept. 23 | 24 | To learn more about Flow, take a look at [its documentation](https://flowtype.org/). 25 | -------------------------------------------------------------------------------- /examples/with-flowtype/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backpack-examples-with-flowtype", 3 | "version": "0.8.4", 4 | "scripts": { 5 | "start": "node ./build/main.js", 6 | "flow": "flow", 7 | "dev": "backpack dev", 8 | "build": "backpack build", 9 | "postinstall": "backpack build" 10 | }, 11 | "license": "MIT", 12 | "dependencies": { 13 | "@babel/core": "^7.1.2", 14 | "@babel/plugin-transform-flow-strip-types": "7.4.4", 15 | "backpack-core": "^0.8.4", 16 | "express": "^4.14.0", 17 | "flow-bin": "^0.101.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/with-flowtype/src/index.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // This will throw an error when you run `npm run flow`. 4 | // change the return type to `:number`, to remove the error. 5 | function foo(x: string, y: number): string { 6 | return x.length * y; 7 | } 8 | 9 | console.log(foo("Hello", 42)); 10 | -------------------------------------------------------------------------------- /examples/with-jest/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "backpack-core/babel" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /examples/with-jest/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /examples/with-jest/README.md: -------------------------------------------------------------------------------- 1 | # Example with Jest 2 | 3 | ## How to use 4 | 5 | Download the example [or clone the whole project](https://github.com/palmerhq/backpack.git): 6 | 7 | ```bash 8 | curl https://codeload.github.com/palmerhq/backpack/tar.gz/master | tar -xz --strip=2 backpack-master/examples/with-jest 9 | cd with-jest 10 | ``` 11 | 12 | Install it and run the tests: 13 | 14 | ```bash 15 | npm install 16 | npm t 17 | ``` 18 | 19 | ## Idea behind the example 20 | 21 | This is an example of how to use the Jest test framework with Backpack. 22 | 23 | **Points of Interest:** 24 | 25 | * New `.babelrc` file with `presets: ["backpack-core/babel"]` 26 | * Add `babel-jest` and `jest-cli` to devDependencies in `package.json` 27 | * Add `"jest"` section to `package.json` to manage Jest configuration 28 | * Demonstrate how to write HTTP test with `supertest-as-promised` 29 | -------------------------------------------------------------------------------- /examples/with-jest/__tests__/createServer.test.js: -------------------------------------------------------------------------------- 1 | /* global it, expect, describe */ 2 | 3 | import createServer from '../src/createServer'; 4 | import request from 'supertest'; 5 | 6 | const app = createServer(); 7 | 8 | describe('Backpack with Jest', () => { 9 | it('Object Rest Spread', () => { 10 | const hello = { hello: 'world' }; 11 | const other = { ...hello, nice: 'to meet you' }; 12 | 13 | expect(other).toEqual({ hello: 'world', nice: 'to meet you' }); 14 | }); 15 | 16 | it('HTTP Request', async () => { 17 | const res = await request(app).get('/'); 18 | expect(res.status).toBe(200); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /examples/with-jest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backpack-examples-with-jest", 3 | "version": "0.8.4", 4 | "scripts": { 5 | "start": "node ./build/main.js", 6 | "test": "NODE_ENV=test jest", 7 | "dev": "backpack dev", 8 | "build": "backpack build", 9 | "postinstall": "backpack build" 10 | }, 11 | "license": "MIT", 12 | "dependencies": { 13 | "@babel/core": "^7.1.2", 14 | "backpack-core": "^0.8.4", 15 | "express": "^4.14.0" 16 | }, 17 | "devDependencies": { 18 | "babel-jest": "^24.8.0", 19 | "jest-cli": "^24.8.0", 20 | "supertest": "^4.0.2" 21 | }, 22 | "jest": { 23 | "testEnvironment": "node", 24 | "transformIgnorePatterns": [ 25 | "[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$" 26 | ], 27 | "globals": { 28 | "__DEV__": true 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/with-jest/src/createServer.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | export default () => { 3 | const app = express(); 4 | 5 | app.get('/', async (req, res) => { 6 | const thing = await Promise.resolve({ one: 'two' }) // async/await! 7 | .catch(e => res.json({ error: e.message })); 8 | return res.json({ ...thing, hello: 'world' }); // object-rest-spread! 9 | }); 10 | 11 | return app; 12 | }; 13 | -------------------------------------------------------------------------------- /examples/with-jest/src/index.js: -------------------------------------------------------------------------------- 1 | import createServer from './createServer' 2 | 3 | const port = process.env.PORT || 3000 4 | const app = createServer() 5 | 6 | app.listen(port, (err) => { 7 | if (err) { 8 | console.error(err) 9 | } 10 | 11 | if (__DEV__) { // webpack flags! 12 | console.log('> in development') 13 | } 14 | console.log(`> listening on port ${port}`) 15 | }) 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/with-typescript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /examples/with-typescript/README.md: -------------------------------------------------------------------------------- 1 | # Custom Webpack Configuration With Typescript Example 2 | 3 | ## How to use 4 | 5 | Download the example (or clone the whole project)[https://github.com/palmerhq/backpack.git]: 6 | 7 | ```bash 8 | curl https://codeload.github.com/palmerhq/backpack/tar.gz/master | tar -xz --strip=2 backpack-master/examples/with-typescript 9 | cd with-typescript 10 | ``` 11 | 12 | Install it and run: 13 | 14 | ```bash 15 | npm install 16 | npm run dev 17 | ``` 18 | 19 | ## Idea behind the example 20 | 21 | This demonstrates how to customize the underlying Webpack 2 configuration in a Backpack project using a `backpack.config.js` file. 22 | The app itself is exactly the same project as the Webpack configuration example. However, the express application is written in TypeScript. 23 | -------------------------------------------------------------------------------- /examples/with-typescript/backpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | webpack: (config, options, webpack) => { 3 | config.entry.main = [ 4 | './src/main.ts' 5 | ] 6 | 7 | config.resolve = { 8 | extensions: [".ts", ".js", ".json"] 9 | }; 10 | 11 | config.module.rules.push( 12 | { 13 | test: /\.ts$/, 14 | loader: 'awesome-typescript-loader' 15 | } 16 | ); 17 | 18 | return config 19 | } 20 | } -------------------------------------------------------------------------------- /examples/with-typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backpack-examples-with-typescript", 3 | "version": "0.8.4", 4 | "scripts": { 5 | "start": "node ./build/main.js", 6 | "dev": "backpack dev", 7 | "build": "backpack build" 8 | }, 9 | "license": "MIT", 10 | "dependencies": { 11 | "@types/express": "^4.0.34", 12 | "awesome-typescript-loader": "^5.2.1", 13 | "backpack-core": "^0.8.4", 14 | "express": "^4.14.0", 15 | "typescript": "^3.5.2" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/with-typescript/src/main.ts: -------------------------------------------------------------------------------- 1 | import * as express from "express" 2 | 3 | declare var __DEV__: boolean; 4 | 5 | export class Server { 6 | public app: express.Express; 7 | public port: number; 8 | 9 | constructor() { 10 | this.app = express(); 11 | this.port = this.getPort(); 12 | this.setRoutes(); 13 | this.start(); 14 | } 15 | 16 | private start = (): void => { 17 | this.app.listen(this.port, this.onListen); 18 | } 19 | 20 | private onListen = (err: any): void => { 21 | if (err) { 22 | console.error(err) 23 | return; 24 | } 25 | 26 | if (__DEV__) { 27 | console.log('> in development') 28 | } 29 | 30 | console.log(`> listening on port ${this.port}`) 31 | }; 32 | 33 | private getPort = (): number => parseInt(process.env.PORT, 10) || 3000; 34 | 35 | private setRoutes = (): void => { 36 | this.app.get('/', this.getHomepage); 37 | } 38 | 39 | private async getHomepage(req: express.Request, res: express.Response): Promise { 40 | try { 41 | const thing = await Promise.resolve({ one: 'two' }) 42 | return res.json({ ...thing, hello: 'world' }) 43 | } catch (e) { 44 | return res.json({ error: e.message }) 45 | } 46 | }; 47 | } 48 | 49 | module.exports = new Server().app; -------------------------------------------------------------------------------- /examples/with-typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "es5", 5 | "es2015.promise" 6 | ] 7 | } 8 | } -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.8.4", 3 | "npmClient": "yarn", 4 | "useWorkspaces": true, 5 | "packages": [ 6 | "packages/*", 7 | "examples/basic*" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "devDependencies": { 4 | "lerna": "^3.15.0" 5 | }, 6 | "scripts": { 7 | "bootstrap-workaround": "lerna exec yarn && lerna link && lerna run prepublish && lerna run prepare", 8 | "postinstall": "yarn bootstrap-workaround", 9 | "bootstrap": "lerna bootstrap", 10 | "clean": "lerna clean", 11 | "purge-lock-files": "rm -rf ./yarn.lock && rm -rf ./**/**/yarn.lock", 12 | "purge-modules": "lerna clean --yes && rm -rf ./node_modules & rm -rf ./tools", 13 | "purge": "yarn purge-modules && yarn purge-lock-files", 14 | "reinstall": "yarn purge && yarn", 15 | "build": "lerna run build --stream --parallel" 16 | }, 17 | "workspaces": [ 18 | "packages/*", 19 | "examples/*" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /packages/babel-preset-backpack/README.md: -------------------------------------------------------------------------------- 1 | # babel-preset-backpack 2 | 3 | This package includes the [Babel](https://babeljs.io) preset used by [Backpack](https://github/com/palmerhq/backpack) 4 | 5 | ## Usage in Backpack Projects 6 | 7 | The easiest way to use this configuration is with Backpack, which includes it by default. **You don’t need to install it separately in Backpack projects.** 8 | 9 | ## Usage Outside of Backpack 10 | 11 | If you want to use this Babel preset in a project not built with Backpack, you can install it with following steps. 12 | 13 | First, [install Babel](https://babeljs.io/docs/setup/). 14 | 15 | Then create a file named `.babelrc` with following contents in the root folder of your project: 16 | 17 | ```js 18 | { 19 | "presets": ["backpack"] 20 | } 21 | ``` 22 | 23 | This preset uses the `useBuiltIns` option with [transform-object-rest-spread](http://babeljs.io/docs/plugins/transform-object-rest-spread/), which assumes that `Object.assign` is available or polyfilled. 24 | 25 | --- 26 | 27 | MIT License 28 | -------------------------------------------------------------------------------- /packages/babel-preset-backpack/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | const path = require('path'); 3 | 4 | const preset = { 5 | presets: [ 6 | [ 7 | require.resolve('@babel/preset-env'), 8 | { 9 | targets: { 10 | node: 'current', 11 | }, 12 | // Webpack takes care of modules, so we don't have to. 13 | modules: false, 14 | }, 15 | ], 16 | ], 17 | plugins: [ 18 | // class { handleThing = () => { } } 19 | require.resolve('@babel/plugin-proposal-class-properties'), 20 | 21 | // The following two plugins use Object.assign directly, instead of Babel's 22 | // extends helper. Note that this assumes `Object.assign` is available. 23 | // { ...todo, completed: true } 24 | [ 25 | require.resolve('@babel/plugin-proposal-object-rest-spread'), 26 | { 27 | useBuiltIns: true, 28 | }, 29 | ], 30 | 31 | [ 32 | require.resolve('@babel/plugin-transform-regenerator'), 33 | { 34 | // Async functions are converted to generators by babel-preset-env (which 35 | // is based on babel-preset-latest) 36 | async: false, 37 | }, 38 | ], 39 | 40 | // This is so we don't need to add `babel-polyfill` to our webpack `entry`. 41 | // Unlike `babel-polyfill`, `babel-runtime` + the transform do not pollute 42 | // the global namespace. Yay. 43 | // @see https://medium.com/@jcse/clearing-up-the-babel-6-ecosystem-c7678a314bf3#.7j10g8yn0 44 | [ 45 | require.resolve('@babel/plugin-transform-runtime'), 46 | { 47 | helpers: false, 48 | regenerator: true, 49 | // Resolve the Babel runtime relative to the config. 50 | absoluteRuntime: path.dirname( 51 | require.resolve('@babel/runtime/package') 52 | ), 53 | }, 54 | ], 55 | ], 56 | }; 57 | 58 | const v = process.versions.node.split('.'); 59 | if ((v[0] >= 7 && v[1] >= 6) || v[0] >= 8) { 60 | preset.presets[0].exclude = [ 61 | '@babel/plugin-transform-regenerator', 62 | '@babel/transform-async-to-generator', 63 | ]; 64 | } 65 | if (process.env.NODE_ENV === 'test' || process.env.BABEL_ENV === 'test') { 66 | preset.plugins.push.apply(preset.plugins, [ 67 | // We always include this plugin regardless of environment 68 | // because of a Babel bug that breaks object rest/spread without it: 69 | // https://github.com/babel/babel/issues/4851 70 | require.resolve('@babel/plugin-transform-parameters'), 71 | // Jest needs this to work properly with import/export syntax 72 | [ 73 | require.resolve('@babel/plugin-transform-modules-commonjs'), 74 | { loose: true }, 75 | ], 76 | ]); 77 | } 78 | 79 | return preset; 80 | }; 81 | -------------------------------------------------------------------------------- /packages/babel-preset-backpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-preset-backpack", 3 | "version": "0.8.4", 4 | "description": "Babel preset for Backpack projects", 5 | "repository": "palmerhq/backpack", 6 | "author": "jaredpalmer", 7 | "license": "MIT", 8 | "homepage": "https://github.com/palmerhq/backpack#readme", 9 | "bugs": { 10 | "url": "https://github.com/palmerhq/backpack/issues" 11 | }, 12 | "files": [ 13 | "index.js" 14 | ], 15 | "dependencies": { 16 | "@babel/core": "^7.4.5", 17 | "@babel/plugin-proposal-class-properties": "^7.4.4", 18 | "@babel/plugin-proposal-object-rest-spread": "^7.4.4", 19 | "@babel/plugin-transform-modules-commonjs": "^7.4.4", 20 | "@babel/plugin-transform-parameters": "^7.4.4", 21 | "@babel/plugin-transform-regenerator": "^7.4.5", 22 | "@babel/plugin-transform-runtime": "^7.4.4", 23 | "@babel/preset-env": "^7.4.5", 24 | "@babel/runtime": "^7.4.5", 25 | "babel-loader": "^8.0.6" 26 | }, 27 | "keywords": [ 28 | "babel", 29 | "es6", 30 | "node", 31 | "backpack" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /packages/backpack-core/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /packages/backpack-core/README.md: -------------------------------------------------------------------------------- 1 | ![backpack](https://cloud.githubusercontent.com/assets/4060187/21872211/318795e8-d835-11e6-8376-bea370605361.png) 2 | 3 | ![backpack-status](https://david-dm.org/palmerhq/backpack.svg?path=packages/backpack-core) 4 | [![npm version](https://badge.fury.io/js/backpack-core.svg)](https://badge.fury.io/js/backpack-core) [![Join the chat at https://gitter.im/palmerhq/backpack](https://badges.gitter.im/palmerhq/backpack.svg)](https://gitter.im/palmerhq/backpack?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | Backpack is minimalistic build system for Node.js. Inspired by Facebook's [create-react-app](https://github.com/facebookincubator/create-react-app), Zeit's [Next.js](https://github.com/zeit/next.js), and Remy's [Nodemon](https://github.com/remy/nodemon), Backpack lets you create modern Node.js apps and services with zero configuration. Backpack handles all the file-watching, live-reloading, transpiling, and bundling, so you don't have to. It comes with a few ~~conventions~~ defaults (like support for the latest JavaScript awesomeness (i.e. async/await, object rest spread, and class properties)), but everything can be customized to fit your project's needs. Best of all, you can easily add Backpack to your existing Node.js project with just a single dependency. 7 | 8 | **Backpack comes with the "battery-pack included":** 9 | 10 | * Latest ES6 features (including module syntax, async/await, object rest spread) 11 | * SUPER friendly, human readable error messages 12 | * Live reload (on saves, add/delete file, etc.) 13 | * Zero-config, one dependency. 14 | 15 | HOWEVER, you can configure Backpack to your project's needs by extending [the underlying Webpack 2 configuration](#custom-configuration). 16 | 17 | ## How to use 18 | 19 | Install it: 20 | 21 | ```bash 22 | npm i backpack-core --save 23 | ``` 24 | 25 | and add a script to your package.json like this: 26 | 27 | ```json 28 | { 29 | "scripts": { 30 | "dev": "backpack" 31 | } 32 | } 33 | ``` 34 | 35 | After that there are just a few ~~conventions~~ defaults: 36 | 37 | * `src/index.js`: the entry of your app. 38 | 39 | ...actually that's it. 40 | 41 | You can then run your application in development mode: 42 | 43 | ```bash 44 | npm run dev 45 | ``` 46 | 47 | Successful builds will show a console like this. _Note: screenshot taken from running the [basic example](https://github.com/palmerhq/backpack/tree/master/examples/basic)_ 48 | npm run dev 49 | 50 | ### Custom configuration 51 | 52 | For custom advanced behavior, you can create a `backpack.config.js` in the root of your project's directory (next to `package.json`). 53 | 54 | ```js 55 | // backpack.config.js 56 | // IMPORTANT: This file is not going through babel transformation. 57 | // You can however use the ES2015 features supported by your Node.js version. 58 | module.exports = { 59 | /* config options here */ 60 | }; 61 | ``` 62 | 63 | ### Customizing webpack config 64 | 65 | [Example](https://github.com/palmerhq/backpack/tree/master/examples/with-custom-webpack-config) 66 | 67 | To extend webpack, you can define a function that extends its config via `backpack.config.js`. 68 | 69 | ```js 70 | // backpack.config.js 71 | module.exports = { 72 | webpack: (config, options, webpack) => { 73 | // Perform customizations to config 74 | // Important: return the modified config 75 | return config; 76 | }, 77 | }; 78 | ``` 79 | 80 | ### Customizing babel config 81 | 82 | [Example](https://github.com/palmerhq/backpack/tree/master/examples/with-custom-babel-config) 83 | 84 | To extend our usage of `babel`, you can define a `.babelrc` file at the root of your app. This file is optional. 85 | 86 | If found, Backpack will consider it to be the _source of truth_. Thus it must define what Backpack needs as well, which is the `backpack-core/babel` preset. 87 | 88 | This is designed so that you are not surprised by modifications we could make to the default `babel` configurations. 89 | 90 | Here's an example `.babelrc` file: 91 | 92 | ```js 93 | { 94 | "presets": [ 95 | "backpack-core", 96 | "stage-0" 97 | ], 98 | } 99 | ``` 100 | 101 | _Note: This works [exactly like Next.js does](https://github.com/zeit/next.js#customizing-babel-config)._ 102 | 103 | ### Building for Production 104 | 105 | Add a npm script for the build step: 106 | 107 | ```json 108 | { 109 | "scripts": { 110 | "dev": "backpack", 111 | "build": "backpack build" 112 | } 113 | } 114 | ``` 115 | 116 | Then run the build command and start your app 117 | 118 | ```bash 119 | npm run build 120 | node ./build/main.js 121 | ``` 122 | 123 | ## CLI Commands 124 | 125 | ### `backpack dev` 126 | 127 | Runs backpack in development mode. 128 | 129 | Your code will reload if you make edits. 130 | You will see the build errors in the console that look like this. 131 | 132 | backpack dev 133 | 134 | ### `backpack build` 135 | 136 | Builds the app for production to the `build` folder. 137 | It correctly bundles your production mode and optimizes the build for the best performance. 138 | 139 | You can run your production application with the following command: 140 | 141 | ```bash 142 | node ./build/main.js 143 | ``` 144 | 145 | Your application is ready to be deployed! 146 | 147 | _Note: Make sure to add the `build` directory to your `.gitignore` to keep compiled code out of your git repository_ 148 | 149 | ## FAQ 150 | 151 |
152 | Is this like Create-React-App or Next.js? 153 | 154 | Yes and No. 155 | 156 | Yes in that they will all make your life easier. 157 | 158 | No in that it that Backpack is focused on server-only applications. You should use create-react-app or Next.js for your frontend and then build your backend with Backpack. 159 | 160 |
161 | 162 |
163 | Can I use this with React to build a universal app? 164 | 165 | Technically, yes. However, we strongly advise against it at the moment. Backpack handles file-watching and reloading in a way that will make things like webpack-hot-middleware annoying to work with. 166 |
167 | 168 |
169 | What syntactic features are transpiled? How do I change them? 170 | 171 | We track V8. Since V8 has wide support for ES6 and async and await, we transpile those. Since V8 doesn’t support class decorators, we don’t transpile those. 172 | 173 | See [this](https://github.com/palmerhq/backpack/blob/master/packages/backpack-core/config/webpack.config.js#L83) and [this](https://github.com/palmerhq/backpack#customizing-webpack) 174 |
175 | 176 |
177 | Why is it called Backpack? 178 | 179 | Backpack is focused on server-only applications. We've been using it for building out Node.js backends and microservices. Under the hood, Webpack and a few other tools make the magic happen. Hence Backend + Webpack = *Backpack*. 180 |
181 | 182 | ## Inspiration 183 | 184 | * [jlongster/backend-with-webpack](https://github.com/jlongster/backend-with-webpack) 185 | * [nyt/kyt](https://github.com/NYTimes/kyt) 186 | * [zeit/next.js](https://github.com/zeit/next.js) 187 | * [facebookincubator/create-react-app](https://github.com/facebookincubator/create-react-app) 188 | 189 | ## Authors 190 | 191 | * Jared Palmer ([@jaredpalmer](https://twitter.com/jaredpalmer)) - The Palmer Group 192 | 193 | --- 194 | 195 | MIT License 196 | -------------------------------------------------------------------------------- /packages/backpack-core/babel.js: -------------------------------------------------------------------------------- 1 | module.exports = require('babel-preset-backpack'); 2 | -------------------------------------------------------------------------------- /packages/backpack-core/bin/backpack: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const path = require('path') 3 | const spawn = require('cross-spawn') 4 | const pkg = require('../package.json') 5 | 6 | const defaultCommand = 'dev' 7 | const commands = new Set([ 8 | 'init', 9 | 'build', 10 | 'start', 11 | defaultCommand 12 | ]) 13 | 14 | let cmd = process.argv[2] 15 | let args 16 | 17 | if (new Set(['--version', '-v']).has(cmd)) { 18 | console.log('backpack v' + pkg.version) 19 | process.exit(0) 20 | } 21 | 22 | if (new Set(['--help', '-h']).has(cmd)) { 23 | console.log(` 24 | Usage 25 | $ backpack 26 | Available commands 27 | ${Array.from(commands).join(', ')} 28 | For more information run a command with the --help flag 29 | $ backpack --help 30 | `) 31 | process.exit(0) 32 | } 33 | 34 | if (commands.has(cmd)) { 35 | args = process.argv.slice(3) 36 | } else { 37 | cmd = defaultCommand 38 | args = process.argv.slice(2) 39 | } 40 | 41 | const bin = path.resolve(path.join(__dirname, cmd)) 42 | 43 | const startProcess = () => { 44 | const proc = spawn(bin, args, { stdio: 'inherit'}) 45 | proc.on('close', (code) => process.exit(code)) 46 | proc.on('error', (err) => { 47 | console.error(err) 48 | process.exit(1) 49 | }) 50 | return proc 51 | } 52 | 53 | const proc = startProcess() 54 | -------------------------------------------------------------------------------- /packages/backpack-core/bin/build: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | const webpack = require('webpack') 3 | const defaultConfig = require('../config/webpack.config') 4 | const path = require('path') 5 | const fs = require('fs') 6 | 7 | process.on('SIGINT', process.exit) 8 | 9 | const options = { 10 | env: process.env.NODE_ENV || 'production' 11 | } 12 | 13 | const configPath = path.resolve('backpack.config.js') 14 | let userConfig = {} 15 | 16 | if (fs.existsSync(configPath)) { 17 | const userConfigModule = require(configPath) 18 | userConfig = userConfigModule.default || userConfigModule 19 | } 20 | 21 | const serverConfig = userConfig.webpack 22 | ? userConfig.webpack(defaultConfig(options), options, webpack) 23 | : defaultConfig(options) 24 | 25 | process.on('SIGINT', process.exit) 26 | 27 | const serverCompiler = webpack(serverConfig) 28 | 29 | serverCompiler.run((error, stats) => { 30 | if (error || stats.hasErrors()) { 31 | process.exitCode = 1; 32 | } 33 | }) 34 | -------------------------------------------------------------------------------- /packages/backpack-core/bin/dev: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | const webpack = require('webpack') 3 | const nodemon = require('nodemon') 4 | const paths = require('../config/paths') 5 | const once = require('ramda').once 6 | const defaultConfig = require('../config/webpack.config') 7 | const path = require('path') 8 | const fs = require('fs') 9 | 10 | const options = { 11 | env: 'development' 12 | } 13 | 14 | const configPath = path.resolve('backpack.config.js') 15 | let userConfig = {} 16 | 17 | if (fs.existsSync(configPath)) { 18 | const userConfigModule = require(configPath) 19 | userConfig = userConfigModule.default || userConfigModule 20 | } 21 | 22 | const serverConfig = userConfig.webpack 23 | ? userConfig.webpack(defaultConfig(options), options, webpack) 24 | : defaultConfig(options) 25 | 26 | process.on('SIGINT', process.exit) 27 | 28 | const serverCompiler = webpack(serverConfig) 29 | 30 | const startServer = () => { 31 | const serverPaths = Object 32 | .keys(serverCompiler.options.entry) 33 | .map(entry => path.join(serverCompiler.options.output.path, `${entry}.js`)) 34 | nodemon({ script: serverPaths[0], watch: serverPaths, nodeArgs: process.argv.slice(2) }) 35 | .on('quit', process.exit) 36 | } 37 | 38 | const startServerOnce = once((err, stats) => { 39 | if (err) return 40 | startServer() 41 | }) 42 | serverCompiler.watch(serverConfig.watchOptions || {}, startServerOnce) 43 | -------------------------------------------------------------------------------- /packages/backpack-core/config/paths.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const rootPath = path.resolve(process.cwd()) 3 | const buildPath = path.join(rootPath, 'build') 4 | const publicBuildPath = path.join(buildPath, 'public') 5 | 6 | module.exports = { 7 | rootPath, 8 | buildPath, 9 | publicBuildPath, 10 | publicSrcPath: path.join(rootPath, 'public'), 11 | serverSrcPath: path.join(rootPath, 'src'), 12 | serverBuildPath: buildPath, 13 | userNodeModulesPath: path.join(rootPath, 'node_modules'), 14 | publicPath: '/', 15 | serverUrl: 'http://localhost:3000' 16 | } 17 | -------------------------------------------------------------------------------- /packages/backpack-core/config/webpack.config.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const webpack = require('webpack'); 3 | const nodeExternals = require('webpack-node-externals'); 4 | const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin'); 5 | const config = require('./paths'); 6 | const path = require('path'); 7 | const babelPreset = require('../babel'); 8 | 9 | // This is the Webpack configuration. 10 | // It is focused on developer experience and fast rebuilds. 11 | module.exports = options => { 12 | const babelRcPath = path.resolve('.babelrc'); 13 | const hasBabelRc = fs.existsSync(babelRcPath); 14 | const mainBabelOptions = { 15 | babelrc: true, 16 | cacheDirectory: true, 17 | presets: [], 18 | }; 19 | 20 | if (hasBabelRc) { 21 | console.log('> Using .babelrc defined in your app root'); 22 | } else { 23 | mainBabelOptions.presets.push(require.resolve('../babel')); 24 | } 25 | 26 | return { 27 | // Webpack v4 add a mode configuration option tells webpack to use its 28 | // built-in optimizations accordingly. 29 | // @see https://webpack.js.org/concepts/mode/ 30 | mode: options.env === 'development' ? 'development' : 'production', 31 | // Webpack can target multiple environments such as `node`, 32 | // `browser`, and even `electron`. Since Backpack is focused on Node, 33 | // we set the default target accordingly. 34 | target: 'node', 35 | // The benefit of Webpack over just using babel-cli or babel-node 36 | // command is sourcemap support. Although it slows down compilation, 37 | // it makes debugging dramatically easier. 38 | devtool: 'source-map', 39 | // Webpack allows you to define externals - modules that should not be 40 | // bundled. When bundling with Webpack for the backend - you usually 41 | // don't want to bundle its node_modules dependencies. This creates an externals 42 | // function that ignores node_modules when bundling in Webpack. 43 | // @see https://github.com/liady/webpack-node-externals 44 | externals: [ 45 | nodeExternals({ 46 | modulesFromFile: true, 47 | whitelist: [ 48 | /\.(eot|woff|woff2|ttf|otf)$/, 49 | /\.(svg|png|jpg|jpeg|gif|ico|webm)$/, 50 | /\.(mp4|mp3|ogg|swf|webp)$/, 51 | /\.(css|scss|sass|less|styl)$/, 52 | ], 53 | }) 54 | ], 55 | // As of Webpack 2 beta, Webpack provides performance hints. 56 | // Since we are not targeting a browser, bundle size is not relevant. 57 | // Additionally, the performance hints clutter up our nice error messages. 58 | performance: { 59 | hints: false, 60 | }, 61 | // Since we are wrapping our own webpack config, we need to properly resolve 62 | // Backpack's and the given user's node_modules without conflict. 63 | resolve: { 64 | extensions: ['.js', '.json'], 65 | // modules: [config.userNodeModulesPath, path.resolve(__dirname, '../node_modules')] 66 | }, 67 | resolveLoader: { 68 | // modules: [config.userNodeModulesPath, path.resolve(__dirname, '../node_modules')] 69 | }, 70 | node: { 71 | __filename: true, 72 | __dirname: true, 73 | }, 74 | entry: { 75 | main: [`${config.serverSrcPath}/index.js`], 76 | }, 77 | // This sets the default output file path, name, and compile target 78 | // module type. Since we are focused on Node.js, the libraryTarget 79 | // is set to CommonJS2 80 | output: { 81 | path: config.serverBuildPath, 82 | filename: '[name].js', 83 | sourceMapFilename: '[name].map', 84 | publicPath: config.publicPath, 85 | libraryTarget: 'commonjs2', 86 | }, 87 | // Define a few default Webpack loaders. Notice the use of the new 88 | // Webpack 2 configuration: module.rules instead of module.loaders 89 | module: { 90 | rules: [ 91 | // Process JS with Babel (transpiles ES6 code into ES5 code). 92 | { 93 | test: /\.(js|jsx)$/, 94 | loader: require.resolve('babel-loader'), 95 | exclude: [/node_modules/, config.buildPath], 96 | options: mainBabelOptions, 97 | }, 98 | ], 99 | }, 100 | // A few commonly used plugins have been removed from Webpack v4. 101 | // Now instead, these plugins are avaliable as "optimizations". 102 | // @see https://webpack.js.org/configuration/optimization/ 103 | optimization: { 104 | // optimization.noEmitOnErrors prevents Webpack 105 | // The NoEmitOnErrorsPlugin plugin prevents Webpack 106 | // from printing out compile time stats to the console. 107 | noEmitOnErrors: true, 108 | }, 109 | plugins: [ 110 | // We define some sensible Webpack flags. One for the Node environment, 111 | // and one for dev / production. These become global variables. Note if 112 | // you use something like eslint or standard in your editor, you will 113 | // want to configure __DEV__ as a global variable accordingly. 114 | new webpack.DefinePlugin({ 115 | 'process.env.NODE_ENV': JSON.stringify(options.env), 116 | __DEV__: options.env === 'development', 117 | }), 118 | // In order to provide sourcemaps, we automagically insert this at the 119 | // top of each file using the BannerPlugin. 120 | new webpack.BannerPlugin({ 121 | raw: true, 122 | entryOnly: false, 123 | banner: `require('${ 124 | // Is source-map-support installed as project dependency, or linked? 125 | require.resolve('source-map-support').indexOf(process.cwd()) === 0 126 | ? // If it's resolvable from the project root, it's a project dependency. 127 | 'source-map-support/register' 128 | : // It's not under the project, it's linked via lerna. 129 | require.resolve('source-map-support/register') 130 | }');`, 131 | }), 132 | // The FriendlyErrorsWebpackPlugin (when combined with source-maps) 133 | // gives Backpack its human-readable error messages. 134 | new FriendlyErrorsWebpackPlugin({ 135 | clearConsole: options.env === 'development', 136 | }), 137 | ], 138 | }; 139 | }; 140 | -------------------------------------------------------------------------------- /packages/backpack-core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backpack-core", 3 | "version": "0.8.4", 4 | "description": "Backpack is a minimalistic build system for Node.js", 5 | "repository": "palmerhq/backpack", 6 | "author": "@jaredpalmer", 7 | "license": "MIT", 8 | "bugs": { 9 | "url": "https://github.com/palmerhq/backpack/issues" 10 | }, 11 | "bin": { 12 | "backpack": "./bin/backpack" 13 | }, 14 | "dependencies": { 15 | "@babel/core": "^7.4.5", 16 | "babel-loader": "^8.0.6", 17 | "babel-preset-backpack": "^0.8.4", 18 | "cross-spawn": "^6.0.5", 19 | "friendly-errors-webpack-plugin": "^1.7.0", 20 | "json-loader": "^0.5.7", 21 | "nodemon": "^1.19.1", 22 | "ramda": "^0.26.1", 23 | "source-map-support": "^0.5.12", 24 | "webpack": "^4.35.0", 25 | "webpack-node-externals": "^1.7.2" 26 | } 27 | } 28 | --------------------------------------------------------------------------------