Skip to content
This repository was archived by the owner on Sep 24, 2020. It is now read-only.

Commit 384ddec

Browse files
author
Matt Levy
authored
Implement hot-reloading without browser refresh. (#29)
* Add dynamic component loading * Add webpack code-splitting * Add manifest and vendor bundles
1 parent 93a4f3c commit 384ddec

File tree

8 files changed

+91
-11
lines changed

8 files changed

+91
-11
lines changed

template/config/webpack.config.base.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ let config = {
88
output: {
99
path: helpers.root('/dist'),
1010
filename: 'js/[name].[hash].js',
11+
chunkFilename: 'js/[name].[hash].js',
1112
publicPath: '/'
1213
},
1314
devtool: 'source-map',

template/config/webpack.config.prod.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const glob = require('glob'),
22
path = require('path'),
3+
CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin'),
34
UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin'),
45
HtmlWebpackPlugin = require('html-webpack-plugin'),
56
CompressionPlugin = require('compression-webpack-plugin'),
@@ -72,6 +73,16 @@ webpackConfig.module.rules[0].options = {
7273
};
7374

7475
webpackConfig.plugins = [...webpackConfig.plugins,
76+
new CommonsChunkPlugin({
77+
name: 'vendor',
78+
minChunks: function(module){
79+
return module.context && module.context.indexOf('node_modules') !== -1;
80+
}
81+
}),
82+
new CommonsChunkPlugin({
83+
name: 'manifest',
84+
minChunks: Infinity
85+
}),
7586
extractSass,
7687
purifyCss,
7788
new HtmlWebpackPlugin({
@@ -92,12 +103,12 @@ webpackConfig.plugins = [...webpackConfig.plugins,
92103
}
93104
}),
94105
new UglifyJsPlugin({
95-
include: /\.min\.js$/,
106+
include: /\.js$/,
96107
minimize: true
97108
}),
98109
new CompressionPlugin({
99110
asset: '[path].gz[query]',
100-
test: /\.min\.js$/
111+
test: /\.js$/
101112
}),
102113
new DefinePlugin({
103114
'process.env': env

template/package-lock.json

Lines changed: 13 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

template/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"coverage:run": "cross-env NODE_ENV=development karma start karma.coverage.js",
2121
"dev": "webpack-dev-server --hot --inline",
2222
"lint": "tslint src/**/*.ts",
23-
"serve": "http-server dist/ -o",
23+
"serve": "http-server dist/ -g -o",
2424
"test": "cross-env NODE_ENV=development karma start karma.unit.js",
2525
"test:debug": "cross-env NODE_ENV=development karma start karma.debug.js",
2626
"test:watch": "cross-env NODE_ENV=development karma start karma.unit.js --singleRun=false --auto-watch"
@@ -37,6 +37,7 @@
3737
"@types/mocha": "~2.2.44",
3838
"@types/node": "~8.0.47",
3939
"@types/sinon": "~2.3.7",
40+
"@types/webpack-env": "^1.13.2",
4041
"autoprefixer": "^7.1.6",
4142
"awesome-typescript-loader": "~3.3.0",
4243
"bootstrap-sass": "^3.3.7",
@@ -84,6 +85,7 @@
8485
"tslint-loader": "~3.5.3",
8586
"typescript": "~2.6.1",
8687
"url-loader": "^0.6.2",
88+
"vue-hot-reload-api": "^2.2.0",
8789
"webpack": "~3.8.1",
8890
"webpack-dev-server": "~2.9.4"
8991
}

template/src/main.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
import Vue from 'vue';
22
import VueRouter from 'vue-router';
3+
import { isHot, makeHot, reload } from './util/hot-reload';
4+
import { createRouter } from './router';
5+
6+
const navbarComponent = () => import('./components/navbar').then(({ NavbarComponent }) => NavbarComponent);
7+
// const navbarComponent = () => import(/* webpackChunkName: 'navbar' */'./components/navbar').then(({ NavbarComponent }) => NavbarComponent);
38

49
import './sass/main.scss';
510

6-
import { HomeComponent } from './components/home';
7-
import { AboutComponent } from './components/about';
8-
import { ListComponent } from './components/list';
9-
import { NavbarComponent } from './components/navbar';
11+
if (process.env.ENV === 'development' && isHot()) {
12+
const navbarModuleId = './components/navbar';
1013

11-
import { createRouter } from './router';
14+
// first arguments for `module.hot.accept` and `require` methods have to be static strings
15+
// see https://github.com/webpack/webpack/issues/5668
16+
makeHot(navbarModuleId, navbarComponent,
17+
module.hot.accept('./components/navbar', () => reload(navbarModuleId, (<any>require('./components/navbar')).NavbarComponent)));
18+
}
1219

1320
new Vue({
1421
el: '#app-main',
1522
router: createRouter(),
1623
components: {
17-
'navbar': NavbarComponent
24+
'navbar': navbarComponent
1825
}
1926
});

template/src/router.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
11
import Vue from 'vue';
22
import VueRouter, { Location, Route, RouteConfig } from 'vue-router';
3+
import { isHot, makeHot, reload } from './util/hot-reload';
34

45
const homeComponent = () => import('./components/home').then(({ HomeComponent }) => HomeComponent);
56
const aboutComponent = () => import('./components/about').then(({ AboutComponent }) => AboutComponent);
67
const listComponent = () => import('./components/list').then(({ ListComponent }) => ListComponent);
8+
// const homeComponent = () => import(/* webpackChunkName: 'home' */'./components/home').then(({ HomeComponent }) => HomeComponent);
9+
// const aboutComponent = () => import(/* webpackChunkName: 'about' */'./components/about').then(({ AboutComponent }) => AboutComponent);
10+
// const listComponent = () => import(/* webpackChunkName: 'list' */'./components/list').then(({ ListComponent }) => ListComponent);
11+
12+
if (process.env.ENV === 'development' && isHot()) {
13+
const homeModuleId = './components/home';
14+
const aboutModuleId = './components/about';
15+
const listModuleId = './components/list';
16+
17+
// first arguments for `module.hot.accept` and `require` methods have to be static strings
18+
// see https://github.com/webpack/webpack/issues/5668
19+
makeHot(homeModuleId, homeComponent,
20+
module.hot.accept('./components/home', () => reload(homeModuleId, (<any>require('./components/home')).HomeComponent)));
21+
22+
makeHot(aboutModuleId, aboutComponent,
23+
module.hot.accept('./components/about', () => reload(aboutModuleId, (<any>require('./components/about')).AboutComponent)));
24+
25+
makeHot(listModuleId, listComponent,
26+
module.hot.accept('./components/list', () => reload(listModuleId, (<any>require('./components/list')).ListComponent)));
27+
}
728

829
Vue.use(VueRouter);
930

template/src/util/hot-reload.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import Vue, { Component } from 'vue';
2+
import * as api from 'vue-hot-reload-api';
3+
4+
export const isHot = () => module.hot;
5+
6+
export async function makeHot(id: string, componentLoader: () => Promise<Component>, acceptFunc: void) {
7+
if (isHot()) {
8+
api.install(Vue);
9+
if (!api.compatible) {
10+
throw new Error('vue-hot-reload-api is not compatible with the version of Vue you are using.');
11+
}
12+
13+
const loadedComponent = await componentLoader();
14+
api.createRecord(id, loadedComponent);
15+
}
16+
}
17+
18+
export function reload(id: string, component: Component) {
19+
api.reload(id, component);
20+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare module 'vue-hot-reload-api' {
2+
import Vue, { Component } from 'vue';
3+
export function install(Vue): void;
4+
export function compatible(): boolean;
5+
export function createRecord(id: string, component: Component): void;
6+
export function reload(id: string, component: Component): void;
7+
}

0 commit comments

Comments
 (0)