
├── .gitignore
├── LICENCE
├── README.md
├── circle.yml
├── deploy-docs.sh
├── docs
├── README.md
├── SUMMARY.md
├── babel.md
├── backend.md
├── commands.md
├── e2e.md
├── env.md
├── linter.md
├── pre-processors.md
├── prerender.md
├── prevent_caching.md
├── proxy.md
├── static.md
├── structure.md
└── unit.md
├── meta.js
├── package.json
├── template
├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .postcssrc.js
├── README.md
├── build
│ ├── build.js
│ ├── check-versions.js
│ ├── dev-client.js
│ ├── dev-server.js
│ ├── load-minified.js
│ ├── service-worker-dev.js
│ ├── service-worker-prod.js
│ ├── utils.js
│ ├── vue-loader.conf.js
│ ├── webpack.base.conf.js
│ ├── webpack.dev.conf.js
│ ├── webpack.prod.conf.js
│ └── webpack.test.conf.js
├── config
│ ├── dev.env.js
│ ├── index.js
│ ├── prod.env.js
│ └── test.env.js
├── index.html
├── package.json
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ └── Hello.vue
│ ├── main.js
│ └── router
│ │ └── index.js
├── static
│ ├── img
│ │ └── icons
│ │ │ ├── android-chrome-192x192.png
│ │ │ ├── android-chrome-512x512.png
│ │ │ ├── apple-touch-icon-120x120.png
│ │ │ ├── apple-touch-icon-152x152.png
│ │ │ ├── apple-touch-icon-180x180.png
│ │ │ ├── apple-touch-icon-60x60.png
│ │ │ ├── apple-touch-icon-76x76.png
│ │ │ ├── apple-touch-icon.png
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── favicon.ico
│ │ │ ├── msapplication-icon-144x144.png
│ │ │ ├── mstile-150x150.png
│ │ │ └── safari-pinned-tab.svg
│ └── manifest.json
└── test
│ ├── e2e
│ ├── custom-assertions
│ │ └── elementCount.js
│ ├── nightwatch.conf.js
│ ├── runner.js
│ └── specs
│ │ └── test.js
│ └── unit
│ ├── .eslintrc
│ ├── index.js
│ ├── karma.conf.js
│ └── specs
│ └── Hello.spec.js
└── test.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | docs/_book
4 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-present, Yuxi (Evan) You
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Maintenance Mode
2 | **The code in this repo is in maintenance mode, with limited plans for future changes. Our focus moving forward is adding PWA support to [Vue CLI 3.0](https://github.com/vuejs/vue-cli/blob/dev/README.md), using its new [`pwa` plugin](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa). We encourage this work to be used for new projects as it is being actively developed. If you have issues with the current codebase, give the new version a spin and let us know what you think.**
3 |
4 | # vue-pwa-boilerplate
5 |
6 | > A full-featured [PWA](https://developers.google.com/web/progressive-web-apps/) template with webpack, hot-reload, lint-on-save, unit testing & css extraction.
7 |
8 | ## Documentation
9 |
10 | - This template builds on top of the main webpack template, so please refer to the [webpack template docs](http://vuejs-templates.github.io/webpack).
11 |
12 | - Check out the [official Vue.js guide](http://vuejs.org/guide/) for general information about Vue that is not specific to this template.
13 |
14 | ## Usage
15 |
16 | This is a project template for [vue-cli](https://github.com/vuejs/vue-cli). **It is recommended to use npm 3+ or [yarn](https://yarnpkg.com) for a more efficient dependency tree.**
17 |
18 | ```bash
19 | $ npm install -g vue-cli
20 | $ vue init pwa my-project
21 | $ cd my-project
22 | $ npm install
23 | $ npm run dev
24 | ```
25 |
26 | This will scaffold the project using the `master` branch. If you wish to use the latest version of the PWA template, do the following instead:
27 |
28 | ``` bash
29 | $ vue init pwa#development my-project
30 | ```
31 |
32 | :warning: **The `development` branch is not considered stable and can contain bugs or not build at all, so use at your own risk.**
33 |
34 | If port 8080 is already in use on your machine you must change the port number in `/config/index.js`. Otherwise `npm run dev` will fail.
35 |
36 | ## What's not Included
37 |
38 | * You should configure your web server to add HTTP headers to prevent caching of critical service worker files.
39 | If you don't do this, [browsers might cache the content for up to 24 hours](https://stackoverflow.com/questions/38843970/service-worker-javascript-update-frequency-every-24-hours/38854905#38854905).
40 | In addition, you should add HTTP headers to prevent the contents of the static folder to be cached unintentionally long.
41 |
42 | See ["Configuring your Web server to prevent caching"](docs/prevent_caching.md) in the docs for more information.
43 |
44 | ## What's Included
45 |
46 | * Service Worker precaching of application shell + static assets (prod)
47 | * Script (async chunk) preloading using ``
48 | * Web Application Manifest + favicons
49 | * Mobile-friendly meta-viewport
50 | * Lighthouse score of 90+/100
51 |
52 | - `npm run dev`: first-in-class development experience.
53 | - Webpack + `vue-loader` for single file Vue components.
54 | - State preserving hot-reload
55 | - State preserving compilation error overlay
56 | - Lint-on-save with ESLint
57 | - Source maps
58 |
59 | - `npm run build`: Production ready build.
60 | - JavaScript minified with [UglifyJS v3](https://github.com/mishoo/UglifyJS2/tree/harmony).
61 | - HTML minified with [html-minifier](https://github.com/kangax/html-minifier).
62 | - CSS across all components extracted into a single file and minified with [cssnano](https://github.com/ben-eb/cssnano).
63 | - All static assets compiled with version hashes for efficient long-term caching, and a production `index.html` is auto-generated with proper URLs to these generated assets.
64 | - Use `npm run build --report`to build with bundle size analytics.
65 | - Generates a Service Worker for offline caching your static assets using [sw-precache-webpack-plugin](https://www.npmjs.com/package/sw-precache-webpack-plugin)
66 |
67 | - `npm run unit`: Unit tests run in PhantomJS with [Karma](http://karma-runner.github.io/0.13/index.html) + [Mocha](http://mochajs.org/) + [karma-webpack](https://github.com/webpack/karma-webpack).
68 | - Supports ES2015+ in test files.
69 | - Supports all webpack loaders.
70 | - Easy mock injection.
71 |
72 | - `npm run e2e`: End-to-end tests with [Nightwatch](http://nightwatchjs.org/).
73 | - Run tests in multiple browsers in parallel.
74 | - Works with one command out of the box:
75 | - Selenium and chromedriver dependencies automatically handled.
76 | - Automatically spawns the Selenium server.
77 |
78 | ### Fork It And Make Your Own
79 |
80 | You can fork this repo to create your own boilerplate, and use it with `vue-cli`:
81 |
82 | ```bash
83 | vue init username/repo my-project
84 | ```
85 |
86 | ## Contributing
87 |
88 | This project is a modified copy of the [`vue-webpack-boilerplate`](https://github.com/vuejs-templates/webpack) template.
89 |
90 | While we welcome contributions from the community, please note that changes to configuration that is shared between this project and `vue-webpack-boilerplate` should be made against `vue-webpack-boilerplate` *first*.
91 |
92 | Once the [upstream](https://stackoverflow.com/a/2739476/385997) PR is merged, please file an additional PR against this project making the equivalent changes. This will help ensure that the shared configuration does not diverge too much.
93 |
94 | Any changes that are specific to this project—related to service workers, or other PWA functionality—do not need an equivalent upstream PR.
95 |
--------------------------------------------------------------------------------
/circle.yml:
--------------------------------------------------------------------------------
1 | machine:
2 | node:
3 | version: stable
4 |
5 | dependencies:
6 | pre:
7 | - sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list'
8 | - sudo apt-get update
9 | - sudo apt-get install google-chrome-stable
10 |
11 | test:
12 | override:
13 | - bash test.sh
14 |
--------------------------------------------------------------------------------
/deploy-docs.sh:
--------------------------------------------------------------------------------
1 | cd docs
2 | rm -rf _book
3 | gitbook build
4 | cd _book
5 | git init
6 | git add -A
7 | git commit -m 'update book'
8 | git push -f git@github.com:vuejs-templates/pwa.git master:gh-pages
9 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | This [Progressive Web Apps](https://developers.google.com/web/progressive-web-apps/) boilerplate is targeted towards large, serious projects and assumes you are somewhat familiar with Webpack and `vue-loader`. Make sure to also read [`vue-loader`'s documentation](http://vuejs.github.io/vue-loader/index.html) for common workflow recipes.
4 |
5 | If you just want to try out `vue-loader` or whip out a quick prototype, use the [webpack-simple](https://github.com/vuejs-templates/webpack-simple) template instead.
6 |
7 | ## Quickstart
8 |
9 | To use this template, scaffold a project with [vue-cli](https://github.com/vuejs/vue-cli). **It is recommended to use npm 3+ for a more efficient dependency tree.**
10 |
11 | ``` bash
12 | $ npm install -g vue-cli
13 | $ vue init pwa my-project
14 | $ cd my-project
15 | $ npm install
16 | $ npm run dev
17 | ```
18 |
--------------------------------------------------------------------------------
/docs/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # Summary
2 |
3 | - [Project Structure](structure.md)
4 | - [Build Commands](commands.md)
5 | - [Babel Configuration](babel.md)
6 | - [Linter Configuration](linter.md)
7 | - [Pre-Processors](pre-processors.md)
8 | - [Handling Static Assets](static.md)
9 | - [Environment Variables](env.md)
10 | - [Integrate with Backend Framework](backend.md)
11 | - [API Proxying During Development](proxy.md)
12 | - [Unit Testing](unit.md)
13 | - [End-to-end Testing](e2e.md)
14 | - [Prerendering for SEO](prerender.md)
15 |
--------------------------------------------------------------------------------
/docs/babel.md:
--------------------------------------------------------------------------------
1 | # Babel Configuration
2 |
3 | This boilerplate uses [`babel-preset-env`](https://www.npmjs.com/package/babel-preset-env) for configuring babel. You can read more about it here - http://2ality.com/2017/02/babel-preset-env.html.
4 |
5 | > A Babel preset that compiles ES2015+ down to ES5 by automatically determining the Babel plugins and polyfills you need based on your targeted browser or runtime environments.
6 |
7 | It uses [`browserslist`](https://github.com/ai/browserslist) to parse this information, so we can use any [valid query format supported by `browserslist`](https://github.com/ai/browserslist#queries).
8 |
9 | However there is a caveat. `browserslist` recommends defining the target in a common place like `package.json` or in a `.browserslistrc` config file. This allows tools like [`autoprefixer`](https://github.com/postcss/autoprefixer) and [`eslint-plugin-compat`](https://github.com/amilajack/eslint-plugin-compat) to share the config. For this template, `browserslist` is configured in the `package.json`:
10 |
11 | ```json
12 | {
13 | "...": "...",
14 | "browserslist": [
15 | "> 1%",
16 | "last 2 versions",
17 | "not ie <= 8"
18 | ]
19 | }
20 | ```
21 |
22 | But the latest stable release of `babel-preset-env`, `v1.6.1` does not support loading the config from `package.json`. So the target environment is repeated in `.babelrc`. If you wish to change your target environment, please be sure to update both `package.json` and `.babelrc`. Note that this has been fixed in the beta version([`@babel/preset-env@7.0.0-beta.34`](https://github.com/babel/babel/tree/master/packages/babel-preset-env)) and the template will be updated once it is out of beta.
23 |
--------------------------------------------------------------------------------
/docs/backend.md:
--------------------------------------------------------------------------------
1 | # Integrating with Backend Framework
2 |
3 | If you are building a purely-static app (one that is deployed separately from the backend API), then you probably don't even need to edit `config/index.js`. However, if you want to integrate this template with an existing backend framework, e.g. Rails/Django/Laravel, which comes with their own project structures, you can edit `config/index.js` to directly generate front-end assets into your backend project.
4 |
5 | Let's take a look at the default `config/index.js`:
6 |
7 | ``` js
8 | 'use strict'
9 |
10 | const path = require('path')
11 |
12 | module.exports = {
13 | build: {
14 | index: path.resolve(__dirname, 'dist/index.html'),
15 | assetsRoot: path.resolve(__dirname, 'dist'),
16 | assetsSubDirectory: 'static',
17 | assetsPublicPath: '/',
18 | productionSourceMap: true
19 | },
20 | dev: {
21 | port: 8080,
22 | proxyTable: {}
23 | }
24 | }
25 | ```
26 |
27 | Inside the `build` section, we have the following options:
28 |
29 | ### `build.index`
30 |
31 | > Must be an absolute path on your local file system.
32 |
33 | This is where the `index.html` (with injected asset URLs) will be generated.
34 |
35 | If you are using this template with a backend-framework, you can edit `index.html` accordingly and point this path to a view file rendered by your backend app, e.g. `app/views/layouts/application.html.erb` for a Rails app, or `resources/views/index.blade.php` for a Laravel app.
36 |
37 | ### `build.assetsRoot`
38 |
39 | > Must be an absolute path on your local file system.
40 |
41 | This should point to the root directory that contains all the static assets for your app. For example, `public/` for both Rails/Laravel.
42 |
43 | ### `build.assetsSubDirectory`
44 |
45 | Nest webpack-generated assets under this directory in `build.assetsRoot`, so that they are not mixed with other files you may have in `build.assetsRoot`. For example, if `build.assetsRoot` is `/path/to/dist`, and `build.assetsSubDirectory` is `static`, then all Webpack assets will be generated in `path/to/dist/static`.
46 |
47 | This directory will be cleaned before each build, so it should only contain assets generated by the build.
48 |
49 | Files inside `static/` will be copied into this directory as-is during build. This means if you change this prefix, all your absolute URLs referencing files in `static/` will also need to be changed. See [Handling Static Assets](static.md) for more details.
50 |
51 | ### `build.assetsPublicPath`
52 |
53 | This should be the URL path where your `build.assetsRoot` will be served from over HTTP. In most cases, this will be root (`/`). Only change this if your backend framework serves static assets with a path prefix. Internally, this is passed to Webpack as `output.publicPath`.
54 |
55 | ### `build.productionSourceMap`
56 |
57 | Whether to generate source maps for production build.
58 |
59 | ### `dev.port`
60 |
61 | Specify the port for the dev server to listen to.
62 |
63 | ### `dev.proxyTable`
64 |
65 | Define proxy rules for the dev server. See [API Proxying During Development](proxy.md) for more details.
66 |
--------------------------------------------------------------------------------
/docs/commands.md:
--------------------------------------------------------------------------------
1 | # Build Commands
2 |
3 | All build commands are executed via [NPM Scripts](https://docs.npmjs.com/misc/scripts).
4 |
5 | ### `npm run dev`
6 |
7 | > Starts a Node.js local development server. See [API Proxying During Development](proxy.md) for more details.
8 |
9 | - Webpack + `vue-loader` for single file Vue components.
10 | - State preserving hot-reload
11 | - State preserving compilation error overlay
12 | - Lint-on-save with ESLint
13 | - Source maps
14 |
15 | ### `npm run build`
16 |
17 | > Build assets for production. See [Integrating with Backend Framework](backend.md) for more details.
18 |
19 | - JavaScript minified with [UglifyJS v3](https://github.com/mishoo/UglifyJS2/tree/harmony).
20 | - HTML minified with [html-minifier](https://github.com/kangax/html-minifier).
21 | - CSS across all components extracted into a single file and minified with [cssnano](https://github.com/ben-eb/cssnano).
22 | - All static assets compiled with version hashes for efficient long-term caching, and a production `index.html` is auto-generated with proper URLs to these generated assets.
23 | - Generates a Service Worker for offline caching your static assets using [sw-precache-webpack-plugin](https://www.npmjs.com/package/sw-precache-webpack-plugin)
24 |
25 | ### `npm run unit`
26 |
27 | > Run unit tests in PhantomJS with [Karma](https://karma-runner.github.io/). See [Unit Testing](unit.md) for more details.
28 |
29 | - Supports ES2015+ in test files.
30 | - Supports all webpack loaders.
31 | - Easy [mock injection](http://vuejs.github.io/vue-loader/en/workflow/testing-with-mocks.html).
32 |
33 | ### `npm run e2e`
34 |
35 | > Run end-to-end tests with [Nightwatch](http://nightwatchjs.org/). See [End-to-end Testing](e2e.md) for more details.
36 |
37 | - Run tests in multiple browsers in parallel.
38 | - Works with one command out of the box:
39 | - Selenium and chromedriver dependencies automatically handled.
40 | - Automatically spawns the Selenium server.
41 |
--------------------------------------------------------------------------------
/docs/e2e.md:
--------------------------------------------------------------------------------
1 | # End-to-end Testing
2 |
3 | This boilerplate uses [Nightwatch.js](http://nightwatchjs.org) for e2e tests. Nightwatch.js is a highly integrated e2e test runner built on top of Selenium. This boilerplate comes with Selenium server and chromedriver binaries pre-configured for you, so you don't have to mess with these yourself.
4 |
5 | Let's take a look at the files in the `test/e2e` directory:
6 |
7 | - `runner.js`
8 |
9 | A Node.js script that starts the dev server, and then launches Nightwatch to run tests against it. This is the script that will run when you run `npm run e2e`.
10 |
11 | - `nightwatch.conf.js`
12 |
13 | Nightwatch configuration file. See [Nightwatch's docs on configuration](http://nightwatchjs.org/guide#settings-file) for more details.
14 |
15 | - `custom-assertions/`
16 |
17 | Custom assertions that can be used in Nightwatch tests. See [Nightwatch's docs on writing custom assertions](http://nightwatchjs.org/guide#writing-custom-assertions) for more details.
18 |
19 | - `specs/`
20 |
21 | Your actual tests! See [Nightwatch's docs on writing tests](http://nightwatchjs.org/guide#writing-tests) and [API reference](http://nightwatchjs.org/api) for more details.
22 |
23 | ### Running Tests in More Browsers
24 |
25 | To configure which browsers to run the tests in, add an entry under "test_settings" in [`test/e2e/nightwatch.conf.js`](https://github.com/vuejs-templates/webpack/blob/master/template/test/e2e/nightwatch.conf.js#L17-L39) , and also the `--env` flag in [`test/e2e/runner.js`](https://github.com/vuejs-templates/webpack/blob/master/template/test/e2e/runner.js#L15). If you wish to configure remote testing on services like SauceLabs, you can either make the Nightwatch config conditional based on environment variables, or use a separate config file altogether. Consult [Nightwatch's docs on Selenium](http://nightwatchjs.org/guide#selenium-settings) for more details.
26 |
--------------------------------------------------------------------------------
/docs/env.md:
--------------------------------------------------------------------------------
1 | # Environment Variables
2 |
3 | Sometimes it is practical to have different config values according to the environment that the application is running in.
4 |
5 | As an example:
6 |
7 | ```js
8 | // config/prod.env.js
9 | module.exports = {
10 | NODE_ENV: '"production"',
11 | DEBUG_MODE: false,
12 | API_KEY: '"..."' // this is shared between all environments
13 | }
14 |
15 | // config/dev.env.js
16 | module.exports = merge(prodEnv, {
17 | NODE_ENV: '"development"',
18 | DEBUG_MODE: true // this overrides the DEBUG_MODE value of prod.env
19 | })
20 |
21 | // config/test.env.js
22 | module.exports = merge(devEnv, {
23 | NODE_ENV: '"testing"'
24 | })
25 | ```
26 |
27 | > **Note:** string variables need to be wrapped into single and double quotes `'"..."'`
28 |
29 | So, the environment variables are:
30 | - Production
31 | - NODE_ENV = 'production',
32 | - DEBUG_MODE = false,
33 | - API_KEY = '...'
34 | - Development
35 | - NODE_ENV = 'development',
36 | - DEBUG_MODE = true,
37 | - API_KEY = '...'
38 | - Testing
39 | - NODE_ENV = 'testing',
40 | - DEBUG_MODE = true,
41 | - API_KEY = '...'
42 |
43 | As we can see, `test.env` inherits the `dev.env` and the `dev.env` inherits the `prod.env`.
44 |
45 | ### Usage
46 |
47 | It is simple to use the environment variables in your code. For example:
48 |
49 | ```js
50 | Vue.config.debug = process.env.DEBUG_MODE
51 | ```
--------------------------------------------------------------------------------
/docs/linter.md:
--------------------------------------------------------------------------------
1 | # Linter Configuration
2 |
3 | This boilerplate uses [ESLint](http://eslint.org/) as the linter, and uses the [Standard](https://github.com/feross/standard/blob/master/RULES.md) preset with some small customizations.
4 |
5 | If you are not happy with the default linting rules, you have several options:
6 |
7 | 1. Overwrite individual rules in `.eslintrc.js`. For example, you can add the following rule to enforce semicolons instead of omitting them:
8 |
9 | ``` js
10 | "semi": [2, "always"]
11 | ```
12 |
13 | 2. Pick a different ESLint preset when generating the project, for example [eslint-config-airbnb](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb).
14 |
15 | 3. Pick "none" for ESLint preset when generating the project and define your own rules. See [ESLint documentation](http://eslint.org/docs/rules/) for more details.
16 |
--------------------------------------------------------------------------------
/docs/pre-processors.md:
--------------------------------------------------------------------------------
1 | # Pre-Processors
2 |
3 | This boilerplate has pre-configured CSS extraction for most popular CSS pre-processors including LESS, SASS, Stylus, and PostCSS. To use a pre-processor, all you need to do is installing the appropriate webpack loader for it. For example, to use SASS:
4 |
5 | ``` bash
6 | npm install sass-loader node-sass --save-dev
7 | ```
8 |
9 | Note you also need to install `node-sass` because `sass-loader` depends on it as a peer dependency.
10 |
11 | ### Using Pre-Processors inside Components
12 |
13 | Once installed, you can use the pre-processors inside your `*.vue` components using the `lang` attribute on `
19 | ```
20 |
21 | ### A note on SASS syntax
22 |
23 | - `lang="scss"` corresponds to the CSS-superset syntax (with curly braces and semicolones).
24 | - `lang="sass"` corresponds to the indentation-based syntax.
25 |
26 | ### PostCSS
27 |
28 | Styles in `*.vue` files are piped through PostCSS by default, so you don't need to use a specific loader for it. You can simply add PostCSS plugins you want to use in `build/webpack.base.conf.js` under the `vue` block:
29 |
30 | ``` js
31 | // build/webpack.base.conf.js
32 | module.exports = {
33 | // ...
34 | vue: {
35 | postcss: [/* your plugins */]
36 | }
37 | }
38 | ```
39 |
40 | See [vue-loader's related documentation](http://vuejs.github.io/vue-loader/en/features/postcss.html) for more details.
41 |
42 | ### Standalone CSS Files
43 |
44 | To ensure consistent extraction and processing, it is recommended to import global, standalone style files from your root `App.vue` component, for example:
45 |
46 | ``` html
47 |
48 |
49 | ```
50 |
51 | Note you should probably only do this for the styles written by yourself for your application. For existing libraries e.g. Bootstrap or Semantic UI, you can place them inside `/static` and reference them directly in `index.html`. This avoids extra build time and also is better for browser caching. (See [Static Asset Handling](static.md))
52 |
--------------------------------------------------------------------------------
/docs/prerender.md:
--------------------------------------------------------------------------------
1 | # Prerendering for SEO
2 |
3 | If you want to prerender routes that will not significantly change once pushed to production, use this Webpack plugin: [prerender-spa-plugin](https://www.npmjs.com/package/prerender-spa-plugin), which has been tested for use with Vue. For pages that _do_ frequently change, [Prerender.io](https://prerender.io/) and [Netlify](https://www.netlify.com/pricing) both offer plans for regularly re-prerendering your content for search engines.
4 |
5 | ## Using `prerender-spa-plugin`
6 |
7 | 1. Install it as a dev dependency:
8 |
9 | ```bash
10 | npm install --save-dev prerender-spa-plugin
11 | ```
12 |
13 | 2. Require it in **build/webpack.prod.conf.js**:
14 |
15 | ```js
16 | // This line should go at the top of the file where other 'imports' live in
17 | const PrerenderSpaPlugin = require('prerender-spa-plugin')
18 | ```
19 |
20 | 3. Configure it in the `plugins` array (also in **build/webpack.prod.conf.js**):
21 |
22 | ```js
23 | new PrerenderSpaPlugin(
24 | // Path to compiled app
25 | path.join(__dirname, '../dist'),
26 | // List of endpoints you wish to prerender
27 | [ '/' ]
28 | )
29 | ```
30 |
31 | If you also wanted to prerender `/about` and `/contact`, then that array would be `[ '/', '/about', '/contact' ]`.
32 |
33 | 4. Enable history mode for `vue-router`:
34 | ```js
35 | const router = new VueRouter({
36 | mode: 'history',
37 | routes: [...]
38 | })
39 | ```
40 |
--------------------------------------------------------------------------------
/docs/prevent_caching.md:
--------------------------------------------------------------------------------
1 | # Configuring your Web server to prevent caching
2 |
3 | ## Why you want to do this
4 |
5 | You should configure your web server to add HTTP headers to prevent caching of critical service worker files.
6 | If you don't do this, [browsers might cache the content for up to 24 hours](https://stackoverflow.com/questions/38843970/service-worker-javascript-update-frequency-every-24-hours/38854905#38854905).
7 |
8 | In addition, you should add HTTP headers to prevent the contents of the static folder to be cached unintentionally long.
9 |
10 | ## Mechanisms at work
11 |
12 | ### Service worker
13 |
14 | When you run the production build and deploy the application to a web server, the browser will call the service worker on the first visit and will download and cache all resources.
15 | When the browser accesses the site a second time, it will use the cached resources.
16 | To notice changes in your app it is crucial that the browser downloads the latest version `service-worker.js` from your server.
17 | The browser will only do this when the [Cache-Control](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching) header associated with `service-worker.js` indicates that a previous download has expired or [24 hours have passed](https://stackoverflow.com/questions/38843970/service-worker-javascript-update-frequency-every-24-hours/38854905#38854905).
18 | If a new service worker is available, it will download the new contents in the background.
19 | Once the download is complete, the default behavior is that the new content will be shown on the next visit of the site.
20 | You can change the template's [`service-worker-prod.js`](../template/build/service-worker-prod.js) to display the message to the user to reload the page, or issue a `window.location.reload()` automatically to trigger an update depending on your application's needs.
21 |
22 | Depending on your setup, you might want to have a short caching time for your service worker or no caching at all.
23 | At minimum, you should add caching headers to disable or minimize caching for `service-worker.js` and `index.html`.
24 |
25 | ### The static folder
26 |
27 | The folder [`static`](../template/static) contains the manifest and the favicons of your app.
28 |
29 | You should limit or disable caching for all files in this folder to ensure users have receive the latest version of these files.
30 |
31 | ### Additional information
32 |
33 | More information about caching headers can be found in the blog post ["Caching best practices & max-age gotchas" by Jake Archibald](https://jakearchibald.com/2016/caching-best-practices/).
34 |
35 | ## How to add caching headers for your server
36 |
37 | Here are some examples that worked for other users of this template.
38 | See [Issue #70](https://github.com/vuejs-templates/pwa/issues/70) for a discussion.
39 |
40 | Apache: Disable all caching for the two essential files
41 |
42 | ` and `background: url(./logo.png)`, `"./logo.png"` is a relative asset path and will be **resolved by Webpack as a module dependency**.
8 |
9 | Because `logo.png` is not JavaScript, when treated as a module dependency, we need to use `url-loader` and `file-loader` to process it. This boilerplate has already configured these loaders for you, so you basically get features such as filename fingerprinting and conditional base64 inlining for free, while being able to use relative/module paths without worrying about deployment.
10 |
11 | Since these assets may be inlined/copied/renamed during build, they are essentially part of your source code. This is why it is recommended to place Webpack-processed static assets inside `/src`, along side other source files. In fact, you don't even have to put them all in `/src/assets`: you can organize them based on the module/component using them. For example, you can put each component in its own directory, with its static assets right next to it.
12 |
13 | ### Asset Resolving Rules
14 |
15 | - **Relative URLs**, e.g. `./assets/logo.png` will be interpreted as a module dependency. They will be replaced with an auto-generated URL based on your Webpack output configuration.
16 |
17 | - **Non-prefixed URLs**, e.g. `assets/logo.png` will be treated the same as the relative URLs and translated into `./assets/logo.png`.
18 |
19 | - **URLs prefixed with `~`** are treated as a module request, similar to `require('some-module/image.png')`. You need to use this prefix if you want to leverage Webpack's module resolving configurations. For example if you have a resolve alias for `assets`, you need to use `
` to ensure that alias is respected.
20 |
21 | - **Root-relative URLs**, e.g. `/assets/logo.png` are not processed at all.
22 |
23 | ### Getting Asset Paths in JavaScript
24 |
25 | In order for Webpack to return the correct asset paths, you need to use `require('./relative/path/to/file.jpg')`, which will get processed by `file-loader` and returns the resolved URL. For example:
26 |
27 | ``` js
28 | computed: {
29 | background () {
30 | return require('./bgs/' + this.id + '.jpg')
31 | }
32 | }
33 | ```
34 |
35 | **Note the above example will include every image under `./bgs/` in the final build.** This is because Webpack cannot guess which of them will be used at runtime, so it includes them all.
36 |
37 | ### "Real" Static Assets
38 |
39 | In comparison, files in `static/` are not processed by Webpack at all: they are directly copied to their final destination as-is, with the same filename. You must reference these files using absolute paths, which is determined by joining `build.assetsPublicPath` and `build.assetsSubDirectory` in `config.js`.
40 |
41 | As an example, with the following default values:
42 |
43 | ``` js
44 | // config.js
45 | module.exports = {
46 | // ...
47 | build: {
48 | assetsPublicPath: '/',
49 | assetsSubDirectory: 'static'
50 | }
51 | }
52 | ```
53 |
54 | Any file placed in `static/` should be referenced using the absolute URL `/static/[filename]`. If you change `assetSubDirectory` to `assets`, then these URLs will need to be changed to `/assets/[filename]`.
55 |
56 | We will learn more about the config file in the section about [backend integration](backend.md).
57 |
--------------------------------------------------------------------------------
/docs/structure.md:
--------------------------------------------------------------------------------
1 | # Project Structure
2 |
3 | ``` bash
4 | .
5 | ├── build/ # webpack config files
6 | │ └── ...
7 | ├── config/
8 | │ ├── index.js # main project config
9 | │ └── ...
10 | ├── src/
11 | │ ├── main.js # app entry file
12 | │ ├── App.vue # main app component
13 | │ ├── components/ # ui components
14 | │ │ └── ...
15 | │ └── assets/ # module assets (processed by webpack)
16 | │ └── ...
17 | ├── static/ # pure static assets (directly copied)
18 | ├── test/
19 | │ └── unit/ # unit tests
20 | │ │ ├── specs/ # test spec files
21 | │ │ ├── index.js # test build entry file
22 | │ │ └── karma.conf.js # test runner config file
23 | │ └── e2e/ # e2e tests
24 | │ │ ├── specs/ # test spec files
25 | │ │ ├── custom-assertions/ # custom assertions for e2e tests
26 | │ │ ├── runner.js # test runner script
27 | │ │ └── nightwatch.conf.js # test runner config file
28 | ├── .babelrc # babel config
29 | ├── .postcssrc.js # postcss config
30 | ├── .eslintrc.js # eslint config
31 | ├── .editorconfig # editor config
32 | ├── index.html # index.html template
33 | └── package.json # build scripts and dependencies
34 | ```
35 |
36 | ### `build/`
37 |
38 | This directory holds the actual configurations for both the development server and the production webpack build. Normally you don't need to touch these files unless you want to customize Webpack loaders, in which case you should probably look at `build/webpack.base.conf.js`.
39 |
40 | ### `config/index.js`
41 |
42 | This is the main configuration file that exposes some of the most common configuration options for the build setup. See [API Proxying During Development](proxy.md) and [Integrating with Backend Framework](backend.md) for more details.
43 |
44 | ### `src/`
45 |
46 | This is where most of your application code will live in. How to structure everything inside this directory is largely up to you; if you are using Vuex, you can consult the [recommendations for Vuex applications](http://vuex.vuejs.org/en/structure.html).
47 |
48 | ### `static/`
49 |
50 | This directory is an escape hatch for static assets that you do not want to process with Webpack. They will be directly copied into the same directory where webpack-built assets are generated.
51 |
52 | See [Handling Static Assets](static.md) for more details.
53 |
54 | ### `test/unit`
55 |
56 | Contains unit test related files. See [Unit Testing](unit.md) for more details.
57 |
58 | ### `test/e2e`
59 |
60 | Contains e2e test related files. See [End-to-end Testing](e2e.md) for more details.
61 |
62 | ### `index.html`
63 |
64 | This is the **template** `index.html` for our single page application. During development and builds, Webpack will generate assets, and the URLs for those generated assets will be automatically injected into this template to render the final HTML.
65 |
66 | ### `package.json`
67 |
68 | The NPM package meta file that contains all the build dependencies and [build commands](commands.md).
69 |
--------------------------------------------------------------------------------
/docs/unit.md:
--------------------------------------------------------------------------------
1 | # Unit Testing
2 |
3 | An overview of the tools used by this boilerplate for unit testing:
4 |
5 | - [Karma](https://karma-runner.github.io/): the test runner that launches browsers, runs the tests and reports the results to us.
6 | - [karma-webpack](https://github.com/webpack/karma-webpack): the plugin for Karma that bundles our tests using Webpack.
7 | - [Mocha](https://mochajs.org/): the test framework that we write test specs with.
8 | - [Chai](http://chaijs.com/): test assertion library that provides better assertion syntax.
9 | - [Sinon](http://sinonjs.org/): test utility library that provides spies, stubs and mocks.
10 |
11 | Chai and Sinon are integrated using [karma-sinon-chai](https://github.com/kmees/karma-sinon-chai), so all Chai interfaces (`should`, `expect`, `assert`) and `sinon` are globally available in test files.
12 |
13 | And the files:
14 |
15 | - `index.js`
16 |
17 | This is the entry file used by `karma-webpack` to bundle all the test code and source code (for coverage purposes). You can ignore it for the most part.
18 |
19 | - `specs/`
20 |
21 | This directory is where you write your actual tests. You can use full ES2015+ and all supported Webpack loaders in your tests.
22 |
23 | - `karma.conf.js`
24 |
25 | This is the Karma configuration file. See [Karma docs](https://karma-runner.github.io/) for more details.
26 |
27 | ## Running Tests in More Browsers
28 |
29 | You can run the tests in multiple real browsers by installing more [karma launchers](https://karma-runner.github.io/1.0/config/browsers.html) and adjusting the `browsers` field in `test/unit/karma.conf.js`.
30 |
31 | ## Mocking Dependencies
32 |
33 | This boilerplate comes with [inject-loader](https://github.com/plasticine/inject-loader) installed by default. For usage with `*.vue` components, see [vue-loader docs on testing with mocks](http://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html).
34 |
--------------------------------------------------------------------------------
/meta.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "helpers": {
3 | "if_or": function (v1, v2, options) {
4 | if (v1 || v2) {
5 | return options.fn(this);
6 | }
7 |
8 | return options.inverse(this);
9 | }
10 | },
11 | "prompts": {
12 | "name": {
13 | "type": "string",
14 | "required": true,
15 | "message": "Project name"
16 | },
17 | "short_name": {
18 | "type": "string",
19 | "required": false,
20 | "message": "Project short name: fewer than 12 characters to not be truncated on homescreens (default: same as name)"
21 | },
22 | "description": {
23 | "type": "string",
24 | "required": false,
25 | "message": "Project description",
26 | "default": "A Vue.js project"
27 | },
28 | "author": {
29 | "type": "string",
30 | "message": "Author"
31 | },
32 | "build": {
33 | "type": "list",
34 | "message": "Vue build",
35 | "choices": [
36 | {
37 | "name": "Runtime + Compiler: recommended for most users",
38 | "value": "standalone",
39 | "short": "standalone"
40 | },
41 | {
42 | "name": "Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .vue files - render functions are required elsewhere",
43 | "value": "runtime",
44 | "short": "runtime"
45 | }
46 | ]
47 | },
48 | "router": {
49 | "type": "confirm",
50 | "message": "Install vue-router?"
51 | },
52 | "lint": {
53 | "type": "confirm",
54 | "message": "Use ESLint to lint your code?"
55 | },
56 | "lintConfig": {
57 | "when": "lint",
58 | "type": "list",
59 | "message": "Pick an ESLint preset",
60 | "choices": [
61 | {
62 | "name": "Standard (https://github.com/feross/standard)",
63 | "value": "standard",
64 | "short": "Standard"
65 | },
66 | {
67 | "name": "Airbnb (https://github.com/airbnb/javascript)",
68 | "value": "airbnb",
69 | "short": "Airbnb"
70 | },
71 | {
72 | "name": "none (configure it yourself)",
73 | "value": "none",
74 | "short": "none"
75 | }
76 | ]
77 | },
78 | "unit": {
79 | "type": "confirm",
80 | "message": "Setup unit tests with Karma + Mocha?"
81 | },
82 | "e2e": {
83 | "type": "confirm",
84 | "message": "Setup e2e tests with Nightwatch?"
85 | }
86 | },
87 | "filters": {
88 | ".eslintrc.js": "lint",
89 | ".eslintignore": "lint",
90 | "config/test.env.js": "unit || e2e",
91 | "test/unit/**/*": "unit",
92 | "build/webpack.test.conf.js": "unit",
93 | "test/e2e/**/*": "e2e",
94 | "src/router/**/*": "router"
95 | },
96 | "completeMessage": "To get started:\n\n {{^inPlace}}cd {{destDirName}}\n {{/inPlace}}npm install\n npm run dev\n\nDocumentation can be found at https://vuejs-templates.github.io/webpack"
97 | };
98 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-cli-template-pwa",
3 | "version": "2.1.0",
4 | "license": "MIT",
5 | "description": "A full-featured Webpack setup with hot-reload, lint-on-save, unit testing & css extraction.",
6 | "scripts": {
7 | "docs": "cd docs && gitbook serve",
8 | "docs:deploy": "bash ./deploy-docs.sh"
9 | },
10 | "devDependencies": {
11 | "vue-cli": "^2.8.1"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/template/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
7 | }
8 | }],
9 | "stage-2"
10 | ],
11 | "plugins": ["transform-runtime"],
12 | "env": {
13 | "test": {
14 | "presets": ["env", "stage-2"],
15 | "plugins": [ "istanbul" ]
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/template/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/template/.eslintignore:
--------------------------------------------------------------------------------
1 | /build/
2 | /config/
3 | /dist/
4 | /*.js
5 | {{#unit}}
6 | /test/unit/coverage/
7 | {{/unit}}
8 |
--------------------------------------------------------------------------------
/template/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // http://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parser: 'babel-eslint',
6 | parserOptions: {
7 | sourceType: 'module'
8 | },
9 | env: {
10 | browser: true,
11 | },
12 | {{#if_eq lintConfig "standard"}}
13 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
14 | extends: 'standard',
15 | {{/if_eq}}
16 | {{#if_eq lintConfig "airbnb"}}
17 | extends: 'airbnb-base',
18 | {{/if_eq}}
19 | // required to lint *.vue files
20 | plugins: [
21 | 'html'
22 | ],
23 | {{#if_eq lintConfig "airbnb"}}
24 | // check if imports actually resolve
25 | 'settings': {
26 | 'import/resolver': {
27 | 'webpack': {
28 | 'config': 'build/webpack.base.conf.js'
29 | }
30 | }
31 | },
32 | {{/if_eq}}
33 | // add your custom rules here
34 | 'rules': {
35 | {{#if_eq lintConfig "standard"}}
36 | // allow paren-less arrow functions
37 | 'arrow-parens': 0,
38 | // allow async-await
39 | 'generator-star-spacing': 0,
40 | {{/if_eq}}
41 | {{#if_eq lintConfig "airbnb"}}
42 | // don't require .vue extension when importing
43 | 'import/extensions': ['error', 'always', {
44 | 'js': 'never',
45 | 'vue': 'never'
46 | }],
47 | // allow optionalDependencies
48 | 'import/no-extraneous-dependencies': ['error', {
49 | 'optionalDependencies': ['test/unit/index.js']
50 | }],
51 | {{/if_eq}}
52 | // allow debugger during development
53 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/template/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | /dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | {{#unit}}
8 | /test/unit/coverage
9 | {{/unit}}
10 | {{#e2e}}
11 | /test/e2e/reports
12 | selenium-debug.log
13 | {{/e2e}}
14 |
15 | # Editor directories and files
16 | .idea
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 |
--------------------------------------------------------------------------------
/template/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | // to edit target browsers: use "browserlist" field in package.json
6 | "autoprefixer": {}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/template/README.md:
--------------------------------------------------------------------------------
1 | # {{ name }}
2 |
3 | > {{ description }}
4 |
5 | ## Build Setup
6 |
7 | ``` bash
8 | # install dependencies
9 | npm install
10 |
11 | # serve with hot reload at localhost:8080
12 | npm run dev
13 |
14 | # build for production with minification
15 | npm run build
16 |
17 | # build for production and view the bundle analyzer report
18 | npm run build --report
19 | {{#unit}}
20 |
21 | # run unit tests
22 | npm run unit
23 | {{/unit}}
24 | {{#e2e}}
25 |
26 | # run e2e tests
27 | npm run e2e
28 | {{/e2e}}
29 | {{#if_or unit e2e}}
30 |
31 | # run all tests
32 | npm test
33 | {{/if_or}}
34 | ```
35 |
36 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
37 |
--------------------------------------------------------------------------------
/template/build/build.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | require('./check-versions')()
4 |
5 | process.env.NODE_ENV = 'production'
6 |
7 | const ora = require('ora')
8 | const rm = require('rimraf')
9 | const path = require('path')
10 | const chalk = require('chalk')
11 | const webpack = require('webpack')
12 | const config = require('../config')
13 | const webpackConfig = require('./webpack.prod.conf')
14 |
15 | const spinner = ora('building for production...')
16 | spinner.start()
17 |
18 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
19 | if (err) throw err
20 | webpack(webpackConfig, function (err, stats) {
21 | spinner.stop()
22 | if (err) throw err
23 | process.stdout.write(stats.toString({
24 | colors: true,
25 | modules: false,
26 | children: false,
27 | chunks: false,
28 | chunkModules: false
29 | }) + '\n\n')
30 |
31 | console.log(chalk.cyan(' Build complete.\n'))
32 | console.log(chalk.yellow(
33 | ' Tip: built files are meant to be served over an HTTP server.\n' +
34 | ' Opening index.html over file:// won\'t work.\n'
35 | ))
36 | })
37 | })
38 |
--------------------------------------------------------------------------------
/template/build/check-versions.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const chalk = require('chalk')
4 | const semver = require('semver')
5 | const packageConfig = require('../package.json')
6 | const shell = require('shelljs')
7 | function exec (cmd) {
8 | return require('child_process').execSync(cmd).toString().trim()
9 | }
10 |
11 | const versionRequirements = [
12 | {
13 | name: 'node',
14 | currentVersion: semver.clean(process.version),
15 | versionRequirement: packageConfig.engines.node
16 | },
17 | ]
18 |
19 | if (shell.which('npm')) {
20 | versionRequirements.push({
21 | name: 'npm',
22 | currentVersion: exec('npm --version'),
23 | versionRequirement: packageConfig.engines.npm
24 | })
25 | }
26 |
27 | module.exports = function () {
28 | const warnings = []
29 | for (let i = 0; i < versionRequirements.length; i++) {
30 | const mod = versionRequirements[i]
31 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
32 | warnings.push(mod.name + ': ' +
33 | chalk.red(mod.currentVersion) + ' should be ' +
34 | chalk.green(mod.versionRequirement)
35 | )
36 | }
37 | }
38 |
39 | if (warnings.length) {
40 | console.log('')
41 | console.log(chalk.yellow('To use this template, you must update following to modules:'))
42 | console.log()
43 | for (let i = 0; i < warnings.length; i++) {
44 | const warning = warnings[i]
45 | console.log(' ' + warning)
46 | }
47 | console.log()
48 | process.exit(1)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/template/build/dev-client.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* eslint-disable */
4 | require('eventsource-polyfill')
5 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
6 |
7 | hotClient.subscribe(function (event) {
8 | if (event.action === 'reload') {
9 | window.location.reload()
10 | }
11 | })
12 |
--------------------------------------------------------------------------------
/template/build/dev-server.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | require('./check-versions')()
4 |
5 | const config = require('../config')
6 | if (!process.env.NODE_ENV) {
7 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV)
8 | }
9 |
10 | const opn = require('opn')
11 | const path = require('path')
12 | const express = require('express')
13 | const webpack = require('webpack')
14 | const proxyMiddleware = require('http-proxy-middleware')
15 | const webpackConfig = {{#if_or unit e2e}}process.env.NODE_ENV === 'testing'
16 | ? require('./webpack.prod.conf')
17 | : {{/if_or}}require('./webpack.dev.conf')
18 |
19 | // default port where dev server listens for incoming traffic
20 | const port = process.env.PORT || config.dev.port
21 | // automatically open browser, if not set will be false
22 | const autoOpenBrowser = !!config.dev.autoOpenBrowser
23 | // Define HTTP proxies to your custom API backend
24 | // https://github.com/chimurai/http-proxy-middleware
25 | const proxyTable = config.dev.proxyTable
26 |
27 | const app = express()
28 | const compiler = webpack(webpackConfig)
29 |
30 | const devMiddleware = require('webpack-dev-middleware')(compiler, {
31 | publicPath: webpackConfig.output.publicPath,
32 | quiet: true
33 | })
34 |
35 | const hotMiddleware = require('webpack-hot-middleware')(compiler, {
36 | log: false
37 | })
38 | // force page reload when html-webpack-plugin template changes
39 | compiler.plugin('compilation', function (compilation) {
40 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
41 | hotMiddleware.publish({ action: 'reload' })
42 | cb()
43 | })
44 | })
45 |
46 | // enable hot-reload and state-preserving
47 | // compilation error display
48 | app.use(hotMiddleware)
49 |
50 | // proxy api requests
51 | Object.keys(proxyTable).forEach(function (context) {
52 | let options = proxyTable[context]
53 | if (typeof options === 'string') {
54 | options = { target: options }
55 | }
56 | app.use(proxyMiddleware(options.filter || context, options))
57 | })
58 |
59 | // handle fallback for HTML5 history API
60 | app.use(require('connect-history-api-fallback')())
61 |
62 | // serve webpack bundle output
63 | app.use(devMiddleware)
64 |
65 | // serve pure static assets
66 | const staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory)
67 | app.use(staticPath, express.static('./static'))
68 |
69 | const uri = 'http://localhost:' + port
70 |
71 | let _resolve
72 | const readyPromise = new Promise(resolve => {
73 | _resolve = resolve
74 | })
75 |
76 | console.log('> Starting dev server...')
77 | devMiddleware.waitUntilValid(() => {
78 | console.log('> Listening at ' + uri + '\n')
79 | // when env is testing, don't need open it
80 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') {
81 | opn(uri)
82 | }
83 | _resolve()
84 | })
85 |
86 | const server = app.listen(port)
87 |
88 | module.exports = {
89 | ready: readyPromise,
90 | close: () => {
91 | server.close()
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/template/build/load-minified.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const fs = require('fs')
4 | const UglifyJS = require('uglify-es')
5 |
6 | module.exports = function(filePath) {
7 | const code = fs.readFileSync(filePath, 'utf-8')
8 | const result = UglifyJS.minify(code)
9 | if (result.error) return ''
10 | return result.code
11 | }
12 |
--------------------------------------------------------------------------------
/template/build/service-worker-dev.js:
--------------------------------------------------------------------------------
1 | // This service worker file is effectively a 'no-op' that will reset any
2 | // previous service worker registered for the same host:port combination.
3 | // In the production build, this file is replaced with an actual service worker
4 | // file that will precache your site's local assets.
5 | // See https://github.com/facebookincubator/create-react-app/issues/2272#issuecomment-302832432
6 |
7 | self.addEventListener('install', () => self.skipWaiting());
8 |
9 | self.addEventListener('activate', () => {
10 | self.clients.matchAll({ type: 'window' }).then(windowClients => {
11 | for (let windowClient of windowClients) {
12 | // Force open pages to refresh, so that they have a chance to load the
13 | // fresh navigation response from the local dev server.
14 | windowClient.navigate(windowClient.url);
15 | }
16 | });
17 | });
--------------------------------------------------------------------------------
/template/build/service-worker-prod.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | 'use strict';
3 |
4 | // Check to make sure service workers are supported in the current browser,
5 | // and that the current page is accessed from a secure origin. Using a
6 | // service worker from an insecure origin will trigger JS console errors.
7 | var isLocalhost = Boolean(window.location.hostname === 'localhost' ||
8 | // [::1] is the IPv6 localhost address.
9 | window.location.hostname === '[::1]' ||
10 | // 127.0.0.1/8 is considered localhost for IPv4.
11 | window.location.hostname.match(
12 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
13 | )
14 | );
15 |
16 | window.addEventListener('load', function() {
17 | if ('serviceWorker' in navigator &&
18 | (window.location.protocol === 'https:' || isLocalhost)) {
19 | navigator.serviceWorker.register('service-worker.js')
20 | .then(function(registration) {
21 | // updatefound is fired if service-worker.js changes.
22 | registration.onupdatefound = function() {
23 | // updatefound is also fired the very first time the SW is installed,
24 | // and there's no need to prompt for a reload at that point.
25 | // So check here to see if the page is already controlled,
26 | // i.e. whether there's an existing service worker.
27 | if (navigator.serviceWorker.controller) {
28 | // The updatefound event implies that registration.installing is set
29 | var installingWorker = registration.installing;
30 |
31 | installingWorker.onstatechange = function() {
32 | switch (installingWorker.state) {
33 | case 'installed':
34 | // At this point, the old content will have been purged and the
35 | // fresh content will have been added to the cache.
36 | // It's the perfect time to display a "New content is
37 | // available; please refresh." message in the page's interface.
38 | break;
39 |
40 | case 'redundant':
41 | throw new Error('The installing ' +
42 | 'service worker became redundant.');
43 |
44 | default:
45 | // Ignore
46 | }
47 | };
48 | }
49 | };
50 | }).catch(function(e) {
51 | console.error('Error during service worker registration:', e);
52 | });
53 | }
54 | });
55 | })();
56 |
--------------------------------------------------------------------------------
/template/build/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const path = require('path')
4 | const config = require('../config')
5 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
6 |
7 | exports.assetsPath = function (_path) {
8 | const assetsSubDirectory = process.env.NODE_ENV === 'production'
9 | ? config.build.assetsSubDirectory
10 | : config.dev.assetsSubDirectory
11 | return path.posix.join(assetsSubDirectory, _path)
12 | }
13 |
14 | exports.cssLoaders = function (options) {
15 | options = options || {}
16 |
17 | const cssLoader = {
18 | loader: 'css-loader',
19 | options: {
20 | minimize: process.env.NODE_ENV === 'production',
21 | sourceMap: options.sourceMap
22 | }
23 | }
24 |
25 | // generate loader string to be used with extract text plugin
26 | function generateLoaders (loader, loaderOptions) {
27 | const loaders = [cssLoader]
28 | if (loader) {
29 | loaders.push({
30 | loader: loader + '-loader',
31 | options: Object.assign({}, loaderOptions, {
32 | sourceMap: options.sourceMap
33 | })
34 | })
35 | }
36 |
37 | // Extract CSS when that option is specified
38 | // (which is the case during production build)
39 | if (options.extract) {
40 | return ExtractTextPlugin.extract({
41 | use: loaders,
42 | fallback: 'vue-style-loader'
43 | })
44 | } else {
45 | return ['vue-style-loader'].concat(loaders)
46 | }
47 | }
48 |
49 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html
50 | return {
51 | css: generateLoaders(),
52 | postcss: generateLoaders(),
53 | less: generateLoaders('less'),
54 | sass: generateLoaders('sass', { indentedSyntax: true }),
55 | scss: generateLoaders('sass'),
56 | stylus: generateLoaders('stylus'),
57 | styl: generateLoaders('stylus')
58 | }
59 | }
60 |
61 | // Generate loaders for standalone style files (outside of .vue)
62 | exports.styleLoaders = function (options) {
63 | const output = []
64 | const loaders = exports.cssLoaders(options)
65 | for (const extension in loaders) {
66 | const loader = loaders[extension]
67 | output.push({
68 | test: new RegExp('\\.' + extension + '$'),
69 | use: loader
70 | })
71 | }
72 | return output
73 | }
74 |
--------------------------------------------------------------------------------
/template/build/vue-loader.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const utils = require('./utils')
4 | const config = require('../config')
5 | const isProduction = process.env.NODE_ENV === 'production'
6 |
7 | module.exports = {
8 | loaders: utils.cssLoaders({
9 | sourceMap: isProduction
10 | ? config.build.productionSourceMap
11 | : config.dev.cssSourceMap,
12 | extract: isProduction
13 | }),
14 | transformToRequire: {
15 | video: 'src',
16 | source: 'src',
17 | img: 'src',
18 | image: 'xlink:href'
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/template/build/webpack.base.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const path = require('path')
4 | const utils = require('./utils')
5 | const config = require('../config')
6 | const vueLoaderConfig = require('./vue-loader.conf')
7 |
8 | function resolve (dir) {
9 | return path.join(__dirname, '..', dir)
10 | }
11 |
12 | module.exports = {
13 | entry: {
14 | app: './src/main.js'
15 | },
16 | output: {
17 | path: config.build.assetsRoot,
18 | filename: '[name].js',
19 | publicPath: process.env.NODE_ENV === 'production'
20 | ? config.build.assetsPublicPath
21 | : config.dev.assetsPublicPath
22 | },
23 | resolve: {
24 | extensions: ['.js', '.vue', '.json'],
25 | alias: {
26 | {{#if_eq build "standalone"}}
27 | 'vue$': 'vue/dist/vue.esm.js',
28 | {{/if_eq}}
29 | '@': resolve('src')
30 | }
31 | },
32 | module: {
33 | rules: [
34 | {{#lint}}
35 | {
36 | test: /\.(js|vue)$/,
37 | loader: 'eslint-loader',
38 | enforce: 'pre',
39 | include: [resolve('src'), resolve('test')],
40 | options: {
41 | formatter: require('eslint-friendly-formatter')
42 | }
43 | },
44 | {{/lint}}
45 | {
46 | test: /\.vue$/,
47 | loader: 'vue-loader',
48 | options: vueLoaderConfig
49 | },
50 | {
51 | test: /\.js$/,
52 | loader: 'babel-loader',
53 | include: [resolve('src'), resolve('test')]
54 | },
55 | {
56 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
57 | loader: 'url-loader',
58 | options: {
59 | limit: 10000,
60 | name: utils.assetsPath('img/[name].[hash:7].[ext]')
61 | }
62 | },
63 | {
64 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
65 | loader: 'url-loader',
66 | options: {
67 | limit: 10000,
68 | name: utils.assetsPath('media/[name].[hash:7].[ext]')
69 | }
70 | },
71 | {
72 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
73 | loader: 'url-loader',
74 | options: {
75 | limit: 10000,
76 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
77 | }
78 | }
79 | ]
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/template/build/webpack.dev.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const fs = require('fs')
4 | const path = require('path')
5 | const utils = require('./utils')
6 | const webpack = require('webpack')
7 | const config = require('../config')
8 | const merge = require('webpack-merge')
9 | const baseWebpackConfig = require('./webpack.base.conf')
10 | const HtmlWebpackPlugin = require('html-webpack-plugin')
11 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
12 |
13 | // add hot-reload related code to entry chunks
14 | Object.keys(baseWebpackConfig.entry).forEach(function (name) {
15 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
16 | })
17 |
18 | module.exports = merge(baseWebpackConfig, {
19 | module: {
20 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
21 | },
22 | // cheap-module-eval-source-map is faster for development
23 | devtool: '#cheap-module-eval-source-map',
24 | plugins: [
25 | new webpack.DefinePlugin({
26 | 'process.env': config.dev.env
27 | }),
28 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
29 | new webpack.HotModuleReplacementPlugin(),
30 | new webpack.NoEmitOnErrorsPlugin(),
31 | // https://github.com/ampedandwired/html-webpack-plugin
32 | new HtmlWebpackPlugin({
33 | filename: 'index.html',
34 | template: 'index.html',
35 | inject: true,
36 | serviceWorkerLoader: ``
38 | }),
39 | new FriendlyErrorsPlugin()
40 | ]
41 | })
42 |
--------------------------------------------------------------------------------
/template/build/webpack.prod.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const fs = require('fs')
4 | const path = require('path')
5 | const utils = require('./utils')
6 | const webpack = require('webpack')
7 | const config = require('../config')
8 | const merge = require('webpack-merge')
9 | const baseWebpackConfig = require('./webpack.base.conf')
10 | const CopyWebpackPlugin = require('copy-webpack-plugin')
11 | const HtmlWebpackPlugin = require('html-webpack-plugin')
12 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
13 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
14 | const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')
15 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
16 | const loadMinified = require('./load-minified')
17 |
18 | const env = {{#if_or unit e2e}}process.env.NODE_ENV === 'testing'
19 | ? require('../config/test.env')
20 | : {{/if_or}}config.build.env
21 |
22 | const webpackConfig = merge(baseWebpackConfig, {
23 | module: {
24 | rules: utils.styleLoaders({
25 | sourceMap: config.build.productionSourceMap,
26 | extract: true
27 | })
28 | },
29 | devtool: config.build.productionSourceMap ? '#source-map' : false,
30 | output: {
31 | path: config.build.assetsRoot,
32 | filename: utils.assetsPath('js/[name].[chunkhash].js'),
33 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
34 | },
35 | plugins: [
36 | // http://vuejs.github.io/vue-loader/en/workflow/production.html
37 | new webpack.DefinePlugin({
38 | 'process.env': env
39 | }),
40 | new UglifyJsPlugin({
41 | uglifyOptions: {
42 | compress: {
43 | warnings: false
44 | }
45 | },
46 | sourceMap: config.build.productionSourceMap,
47 | parallel: true
48 | }),
49 | // extract css into its own file
50 | new ExtractTextPlugin({
51 | filename: utils.assetsPath('css/[name].[contenthash].css')
52 | }),
53 | // Compress extracted CSS. We are using this plugin so that possible
54 | // duplicated CSS from different components can be deduped.
55 | new OptimizeCSSPlugin({
56 | cssProcessorOptions: {
57 | safe: true
58 | }
59 | }),
60 | // generate dist index.html with correct asset hash for caching.
61 | // you can customize output by editing /index.html
62 | // see https://github.com/ampedandwired/html-webpack-plugin
63 | new HtmlWebpackPlugin({
64 | filename: {{#if_or unit e2e}}process.env.NODE_ENV === 'testing'
65 | ? 'index.html'
66 | : {{/if_or}}config.build.index,
67 | template: 'index.html',
68 | inject: true,
69 | minify: {
70 | removeComments: true,
71 | collapseWhitespace: true,
72 | removeAttributeQuotes: true
73 | // more options:
74 | // https://github.com/kangax/html-minifier#options-quick-reference
75 | },
76 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin
77 | chunksSortMode: 'dependency',
78 | serviceWorkerLoader: ``
80 | }),
81 | // split vendor js into its own file
82 | new webpack.optimize.CommonsChunkPlugin({
83 | name: 'vendor',
84 | minChunks: function (module, count) {
85 | // any required modules inside node_modules are extracted to vendor
86 | return (
87 | module.resource &&
88 | /\.js$/.test(module.resource) &&
89 | module.resource.indexOf(
90 | path.join(__dirname, '../node_modules')
91 | ) === 0
92 | )
93 | }
94 | }),
95 | // extract webpack runtime and module manifest to its own file in order to
96 | // prevent vendor hash from being updated whenever app bundle is updated
97 | new webpack.optimize.CommonsChunkPlugin({
98 | name: 'manifest',
99 | chunks: ['vendor']
100 | }),
101 | // copy custom static assets
102 | new CopyWebpackPlugin([
103 | {
104 | from: path.resolve(__dirname, '../static'),
105 | to: config.build.assetsSubDirectory,
106 | ignore: ['.*']
107 | }
108 | ]),
109 | // service worker caching
110 | new SWPrecacheWebpackPlugin({
111 | cacheId: '{{ name }}',
112 | filename: 'service-worker.js',
113 | staticFileGlobs: ['dist/**/*.{js,html,css}'],
114 | minify: true,
115 | stripPrefix: 'dist/'
116 | })
117 | ]
118 | })
119 |
120 | if (config.build.productionGzip) {
121 | const CompressionWebpackPlugin = require('compression-webpack-plugin')
122 |
123 | webpackConfig.plugins.push(
124 | new CompressionWebpackPlugin({
125 | asset: '[path].gz[query]',
126 | algorithm: 'gzip',
127 | test: new RegExp(
128 | '\\.(' +
129 | config.build.productionGzipExtensions.join('|') +
130 | ')$'
131 | ),
132 | threshold: 10240,
133 | minRatio: 0.8
134 | })
135 | )
136 | }
137 |
138 | if (config.build.bundleAnalyzerReport) {
139 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
140 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
141 | }
142 |
143 | module.exports = webpackConfig
144 |
--------------------------------------------------------------------------------
/template/build/webpack.test.conf.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | // This is the webpack config used for unit tests.
4 |
5 | const utils = require('./utils')
6 | const webpack = require('webpack')
7 | const merge = require('webpack-merge')
8 | const baseConfig = require('./webpack.base.conf')
9 |
10 | const webpackConfig = merge(baseConfig, {
11 | // use inline sourcemap for karma-sourcemap-loader
12 | module: {
13 | rules: utils.styleLoaders()
14 | },
15 | devtool: '#inline-source-map',
16 | resolveLoader: {
17 | alias: {
18 | // necessary to to make lang="scss" work in test when using vue-loader's ?inject option
19 | // see discussion at https://github.com/vuejs/vue-loader/issues/724
20 | 'scss-loader': 'sass-loader'
21 | }
22 | },
23 | plugins: [
24 | new webpack.DefinePlugin({
25 | 'process.env': require('../config/test.env')
26 | })
27 | ]
28 | })
29 |
30 | // no need for app entry during tests
31 | delete webpackConfig.entry
32 |
33 | module.exports = webpackConfig
34 |
--------------------------------------------------------------------------------
/template/config/dev.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const merge = require('webpack-merge')
4 | const prodEnv = require('./prod.env')
5 |
6 | module.exports = merge(prodEnv, {
7 | NODE_ENV: '"development"'
8 | })
9 |
--------------------------------------------------------------------------------
/template/config/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | // see http://vuejs-templates.github.io/webpack for documentation.
4 | const path = require('path')
5 |
6 | module.exports = {
7 | build: {
8 | env: require('./prod.env'),
9 | index: path.resolve(__dirname, '../dist/index.html'),
10 | assetsRoot: path.resolve(__dirname, '../dist'),
11 | assetsSubDirectory: 'static',
12 | assetsPublicPath: '/',
13 | productionSourceMap: true,
14 | // Gzip off by default as many popular static hosts such as
15 | // Surge or Netlify already gzip all static assets for you.
16 | // Before setting to `true`, make sure to:
17 | // npm install --save-dev compression-webpack-plugin
18 | productionGzip: false,
19 | productionGzipExtensions: ['js', 'css'],
20 | // Run the build command with an extra argument to
21 | // View the bundle analyzer report after build finishes:
22 | // `npm run build --report`
23 | // Set to `true` or `false` to always turn it on or off
24 | bundleAnalyzerReport: process.env.npm_config_report
25 | },
26 | dev: {
27 | env: require('./dev.env'),
28 | port: 8080,
29 | autoOpenBrowser: true,
30 | assetsSubDirectory: 'static',
31 | assetsPublicPath: '/',
32 | proxyTable: {},
33 | // CSS Sourcemaps off by default because relative paths are "buggy"
34 | // with this option, according to the CSS-Loader README
35 | // (https://github.com/webpack/css-loader#sourcemaps)
36 | // In our experience, they generally work as expected,
37 | // just be aware of this issue when enabling this option.
38 | cssSourceMap: false
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/template/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/template/config/test.env.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const merge = require('webpack-merge')
4 | const devEnv = require('./dev.env')
5 |
6 | module.exports = merge(devEnv, {
7 | NODE_ENV: '"testing"'
8 | })
9 |
--------------------------------------------------------------------------------
/template/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |