Skip to content

Commit e2894d4

Browse files
committed
2.0
1 parent b0d20cd commit e2894d4

23 files changed

+781
-0
lines changed

.babelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["env", "react", "stage-1"]
3+
}

.gitignore

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#### joe made this: http://goel.io/joe
2+
3+
#####=== Node ===#####
4+
5+
# Logs
6+
logs
7+
*.log
8+
9+
# Runtime data
10+
pids
11+
*.pid
12+
*.seed
13+
14+
# Directory for instrumented libs generated by jscoverage/JSCover
15+
lib-cov
16+
17+
# Coverage directory used by tools like istanbul
18+
coverage
19+
20+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21+
.grunt
22+
23+
# node-waf configuration
24+
.lock-wscript
25+
26+
# Compiled binary addons (http://nodejs.org/api/addons.html)
27+
build/Release
28+
29+
# Dependency directory
30+
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
31+
node_modules
32+
33+
# Debug log from npm
34+
npm-debug.log
35+

404.html

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>Single Page Apps for GitHub Pages</title>
6+
<script type="text/javascript">
7+
// Single Page Apps for GitHub Pages
8+
// https://github.com/rafrex/spa-github-pages
9+
// Copyright (c) 2016 Rafael Pedicini, licensed under the MIT License
10+
// ----------------------------------------------------------------------
11+
// This script takes the current url and converts the path and query
12+
// string into just a query string, and then redirects the browser
13+
// to the new url with only a query string and hash fragment,
14+
// e.g. http://www.foo.tld/one/two?a=b&c=d#qwe, becomes
15+
// http://www.foo.tld/?p=/one/two&q=a=b~and~c=d#qwe
16+
// Note: this 404.html file must be at least 512 bytes for it to work
17+
// with Internet Explorer (it is currently > 512 bytes)
18+
19+
// If you're creating a Project Pages site and NOT using a custom domain,
20+
// then set segmentCount to 1 (enterprise users may need to set it to > 1).
21+
// This way the code will only replace the route part of the path, and not
22+
// the real directory in which the app resides, for example:
23+
// https://username.github.io/repo-name/one/two?a=b&c=d#qwe becomes
24+
// https://username.github.io/repo-name/?p=/one/two&q=a=b~and~c=d#qwe
25+
// Otherwise, leave segmentCount as 0.
26+
var segmentCount = 0;
27+
28+
var l = window.location;
29+
l.replace(
30+
l.protocol + '//' + l.hostname + (l.port ? ':' + l.port : '') +
31+
l.pathname.split('/').slice(0, 1 + segmentCount).join('/') + '/?p=/' +
32+
l.pathname.slice(1).split('/').slice(segmentCount).join('/').replace(/&/g, '~and~') +
33+
(l.search ? '&q=' + l.search.slice(1).replace(/&/g, '~and~') : '') +
34+
l.hash
35+
);
36+
37+
</script>
38+
</head>
39+
<body>
40+
</body>
41+
</html>

CNAME

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
spa-github-pages.rafrex.com

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016 Rafael Pedicini
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.

README.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Single Page Apps for GitHub Pages
2+
3+
[Live example][liveExample]
4+
5+
This is a lightweight solution for deploying single page apps with [GitHub Pages][ghPagesOverview]. You can easily deploy a [React][react] single page app with [React Router][reactRouter] `<BrowserRouter />`, like the one in the [live example][liveExample], or a single page app built with any frontend library or framework.
6+
7+
#### Why it's necessary
8+
GitHub Pages doesn't natively support single page apps. When there is a fresh page load for a url like `example.tld/foo`, where `/foo` is a frontend route, the GitHub Pages server returns 404 because it knows nothing of `/foo`.
9+
10+
#### How it works
11+
When the GitHub Pages server gets a request for a path defined with frontend routes, e.g. `example.tld/foo`, it returns a custom `404.html` page. The [custom `404.html` page contains a script][404html] that takes the current url and converts the path and query string into just a query string, and then redirects the browser to the new url with only a query string and hash fragment. For example, `example.tld/one/two?a=b&c=d#qwe`, becomes `example.tld/?p=/one/two&q=a=b~and~c=d#qwe`.
12+
13+
The GitHub Pages server receives the new request, e.g. `example.tld?p=/...`, ignores the query string and hash fragment and returns the `index.html` file, which has a [script that checks for a redirect in the query string][indexHtmlScript] before the single page app is loaded. If a redirect is present it is converted back into the correct url and added to the browser's history with `window.history.replaceState(...)`, but the browser won't attempt to load the new url. When the [single page app is loaded][indexHtmlSPA] further down in the `index.html` file, the correct url will be waiting in the browser's history for the single page app to route accordingly. (Note that these redirects are only needed with fresh page loads, and not when navigating within the single page app once it's loaded).
14+
15+
A quick SEO note - while it's never good to have a 404 response, it appears based on [Search Engine Land's testing][seoLand] that Google's crawler will treat the JavaScript `window.location` redirect in the `404.html` file the same as a 301 redirect for its indexing. From my testing I can confirm that Google will index all pages without issue, the only caveat is that the redirect query is what Google indexes as the url. For example, the url `example.tld/about` will get indexed as `example.tld/?p=/about`. When the user clicks on the search result, the url will change back to `example.tld/about` once the site loads.
16+
17+
18+
## Usage instructions
19+
*For general information on using GitHub Pages please see [GitHub Pages Basics][ghPagesBasics], note that pages can be [User, Organization or Project Pages][ghPagesTypes]*
20+
&nbsp;
21+
22+
**Basic instructions** - there are two things you need from this repo for your single page app to run on GitHub Pages
23+
1. Copy over the [`404.html`][404html] file to your repo as is
24+
- Note that if you are setting up a Project Pages site and not using a [custom domain][customDomain] (i.e. your site's address is `username.github.io/repo-name`), then you need to set [`segmentCount` to `1` in the `404.html` file][segmentCount] in order to keep `/repo-name` in the path after the redirect.
25+
2. Copy the [redirect script][indexHtmlScript] in the `index.html` file and add it to your `index.html` file
26+
- Note that the redirect script must be placed *before* your single page app script in your `index.html` file
27+
&nbsp;
28+
29+
**Detailed instructions** - using this repo as a boilerplate for a React single page app hosted with GitHub Pages
30+
1. Clone this repo (`$ git clone https://github.com/rafrex/spa-github-pages.git`)
31+
2. Delete the `.git` directory (`cd` into the `spa-github-pages` directory and run `$ rm -rf .git`)
32+
3. Instantiate the repository
33+
- If you're using this boilerplate as a new repository
34+
- `$ git init` in the `spa-github-pages` directory, and then `$ git add .` and `$ git commit -m "Add SPA for GitHub Pages boilerplate"` to initialize a fresh repository
35+
- If this will be a Project Pages site, then change the branch name from `master` to `gh-pages` (`$ git branch -m gh-pages`), if this will be a User or Organization Pages site, then leave the branch name as `master`
36+
- Create an empty repo on GitHub.com (don't add a readme, gitignore or license), and add it as a remote to the local repo (`$ git remote add origin <your-new-github-repo-url>`)
37+
- Feel free to rename the local `spa-github-pages` directory to anything you want (e.g. `your-project-name`)
38+
- If you're adding this boilerplate as the `gh-pages` branch of an existing repository
39+
- Create and checkout a new orphaned branch named `gh-pages` for your existing repo (`$ git checkout --orphan gh-pages`), note that the `gh-pages` branch won't appear in the list of branches until you make your first commit
40+
- Delete all of the files and directories (except the `.git` directory) from the directory of your existing repo (`$ git rm -rf .`)
41+
- Copy all of the files and directories (including hidden dot files) from the cloned `spa-github-pages` directory into your project's now empty directory (`$ mv path/to/spa-github-pages/{.[!.],}* path/to/your-projects-directory`)
42+
- `$ git add .` and `$ git commit -m "Add SPA for GitHub Pages boilerplate"` to instantiate the `gh-pages` branch
43+
4. Set up a custom domain (optional) - see GitHub Pages instructions for [setting up a custom domain][customDomain]
44+
- Update the [`CNAME` file][cnameFile] with your custom domain, don't include `http://`, but do include a subdomain if desired, e.g. `www` or `your-subdomain`
45+
- Update your `CNAME` and/or `A` record with your DNS provider
46+
- Run `$ dig your-subdomain.your-domain.tld` to make sure it's set up properly with your DNS (don't include `http://`)
47+
5. Set up without using a custom domain (optional)
48+
- Delete the [`CNAME` file][cnameFile]
49+
- If you are creating a User or Organization Pages site, then that's all you need to do
50+
- If you are creating a Project Pages site, (i.e. your site's address is `username.github.io/repo-name`):
51+
- Set [`segmentCount` to `1` in the `404.html` file][segmentCount] in order to keep `/repo-name` in the path after the redirect
52+
- Add your `repo-name` to the absolute path of assets in `index.html`
53+
- Change the [bundle.js src][indexHtmlSPA] to `"/repo-name/build/bundle.js"`
54+
- If you are using React Router you'll need to tell it to use the `repo-name` as the `basename`, for example `<BrowserRouter basename="/repo-name" />`
55+
6. Run `$ npm install` to install React and other dependencies, and then run `$ npm run build` to update the build
56+
7. `$ git add .` and `$ git commit -m "Update boilerplate for use with my domain"` and then push to GitHub (`$ git push origin gh-pages` for Project Pages or `$ git push origin master` for User or Organization Pages) - the example site should now be live on your domain
57+
8. Create your own site
58+
- Write your own React components, create your own routes, and add your own style
59+
- Note that the example site is created with all inline styles and uses [React Interactive][reactInteractive] for the links and other interactive components (there is no CSS except for a reset in `index.html`)
60+
- Change the [title in `index.html`][indexHtmlTitle] and the [title in `404.html`][404htmlTitle] to your site's title
61+
- Remove the [favicon links][favicon] from the header of `index.html`
62+
- Change the readme, license and package.json as you see fit
63+
- For testing changes locally see development environment info below
64+
- To publish your changes to GitHub Pages run `$ npm run build` (this runs `webpack -p` for [production][webpackProduction]) to update the build, then `$ git commit` and `$ git push` to make your changes live
65+
66+
67+
#### Development environment
68+
I have included `webpack-dev-server` for testing changes locally. It can be accessed by running `$ npm start` (details below), or you can use your own dev setup by running `$ webpack` and serving the `index.html` file and the `404.html` file for 404s. Note that `webpack-dev-server` automatically creates a new bundle whenever the source files change and serves the bundle from memory, so you'll never see the bundle as a file saved to disk.
69+
- `$ npm start` runs the [start script][startScript] in `package.json`, which runs the command `$ webpack-dev-server --devtool eval-source-map --history-api-fallback --open`
70+
- `-devtool eval-source-map` is for [generating source maps][webpackDevtool] in while in development
71+
- `--history-api-fallback` allows for frontend routing and will serve `index.html` when the requested file can't be found
72+
- `--open` will open automatically open the site in your browser
73+
- `webpack-dev-server` will serve `index.html` at `http://localhost:8080` (port `8080` is the default). Note that you must load the `index.html` from the server and not just open it directly in the browser or the scripts won't load.
74+
75+
#### Miscellaneous
76+
- The `.nojekyll` file in this repo [turns off Jekyll for GitHub Pages][nojekyll]
77+
- Need form submission on your static site? Use [Formspree][formspree]
78+
- One of the great things about the GitHub Pages CDN is that all files are automatically compressed with gzip, so no need to worry about compressing your JavaScript, HTML or CSS files for production
79+
80+
81+
<!-- links to within repo -->
82+
[404html]: https://github.com/rafrex/spa-github-pages/blob/gh-pages/404.html
83+
[segmentCount]: https://github.com/rafrex/spa-github-pages/blob/gh-pages/404.html#L26
84+
[indexHtmlScript]: https://github.com/rafrex/spa-github-pages/blob/gh-pages/index.html#L58
85+
[indexHtmlSPA]: https://github.com/rafrex/spa-github-pages/blob/gh-pages/index.html#L94
86+
[cnameFile]: https://github.com/rafrex/spa-github-pages/blob/gh-pages/CNAME
87+
[indexHtmlTitle]: https://github.com/rafrex/spa-github-pages/blob/gh-pages/index.html#L6
88+
[404htmlTitle]: https://github.com/rafrex/spa-github-pages/blob/gh-pages/404.html#L5
89+
[favicon]: https://github.com/rafrex/spa-github-pages/blob/gh-pages/index.html#L34
90+
[startScript]: https://github.com/rafrex/spa-github-pages/blob/gh-pages/package.json#L6
91+
92+
<!-- links to github docs -->
93+
[ghPagesOverview]: https://pages.github.com/
94+
[ghPagesBasics]: https://help.github.com/categories/github-pages-basics/
95+
[ghPagesTypes]: https://help.github.com/articles/user-organization-and-project-pages/
96+
[customDomain]: https://help.github.com/articles/quick-start-setting-up-a-custom-domain/
97+
[nojekyll]: https://help.github.com/articles/files-that-start-with-an-underscore-are-missing/
98+
99+
<!-- other links -->
100+
[liveExample]: http://spa-github-pages.rafrex.com
101+
[react]: https://github.com/facebook/react
102+
[reactRouter]: https://github.com/ReactTraining/react-router
103+
[seoLand]: http://searchengineland.com/tested-googlebot-crawls-javascript-heres-learned-220157
104+
[webpackProduction]: https://webpack.js.org/guides/production-build/#the-automatic-way
105+
[webpackDevtool]: https://webpack.js.org/configuration/devtool/
106+
[reactInteractive]: https://github.com/rafrex/react-interactive
107+
[formspree]: http://formspree.io/

build/bundle.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)