Skip to content

Commit

Permalink
Add hot example
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnyreilly committed Oct 20, 2017
1 parent cb33f9d commit 2e2f29a
Show file tree
Hide file tree
Showing 26 changed files with 6,395 additions and 29 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -13,7 +13,7 @@ This is the typescript loader for webpack.

### Examples

We have a number of example setups to accomodate different workflows. From "[vanilla](examples/vanilla)" ts-loader, to using ts-loader in combination with [babel](https://babeljs.io/) for transpilation, [happypack](https://github.com/amireh/happypack) or [thread-loader](https://github.com/webpack-contrib/thread-loader) for faster builds and [fork-ts-checker-webpack-plugin](https://github.com/Realytics/fork-ts-checker-webpack-plugin) for performing type checking in a separate process. Our examples can be found [here](examples/).
We have a number of example setups to accomodate different workflows. From "[vanilla](examples/vanilla)" ts-loader, to using ts-loader in combination with [babel](https://babeljs.io/) for transpilation, [happypack](https://github.com/amireh/happypack) or [thread-loader](https://github.com/webpack-contrib/thread-loader) for faster builds and [fork-ts-checker-webpack-plugin](https://github.com/Realytics/fork-ts-checker-webpack-plugin) for performing type checking in a separate process. Not forgetting [Hot Module Replacement](https://webpack.js.org/api/hot-module-replacement/). Our examples can be found [here](examples/).

### Babel

Expand Down
18 changes: 18 additions & 0 deletions examples/hot/README.md
@@ -0,0 +1,18 @@
# Hot Module Reloading / Jest

## Getting started

You'll need [node / npm](https://nodejs.org/) installed. To get up and running just enter:

```shell
# Download the npm packages you need (including the type definitions from DefinitelyTyped)
yarn install

# Compile the code and serve it up at http://localhost:8080 with hot module reloading activated - just tweak the code in app.tsx to see this
yarn start

# If you'd like to run your tests in watch mode then fire up a separate console and enter this command:
yarn test:watch
```

When you're building for production then `yarn build`. To run tests in CI then `yarn test`
23 changes: 23 additions & 0 deletions examples/hot/internal/tests/browserMocks.js
@@ -0,0 +1,23 @@
var localStorageMock = (function() {
var store = {};

return {
getItem: function(key) {
return store[key] || null;
},
setItem: function(key, value) {
store[key] = value.toString();
},
removeItem: function(key) {
delete this.store[key]
},
clear: function() {
store = {};
}
};

})();

Object.defineProperty(window, 'localStorage', {
value: localStorageMock
});
1 change: 1 addition & 0 deletions examples/hot/internal/tests/fileMock.js
@@ -0,0 +1 @@
module.exports = 'test-file-stub';
3 changes: 3 additions & 0 deletions examples/hot/internal/tests/styleMock.js
@@ -0,0 +1,3 @@
module.exports = {
isDanger: 'dangerDanger'
};
24 changes: 24 additions & 0 deletions examples/hot/internal/webpack/shared.js
@@ -0,0 +1,24 @@
/**
* Given an array of files this will produce an object which contains the values for the vendor entry point
*/
function makeVendorEntry(config) {
const packageJson = require('../../package.json');
const vendorDependencies = Object.keys(packageJson['dependencies']);

// config example value:
// {
// mainModules: [
// 'core-js',
// 'whatwg-fetch',
// 'react-hot-loader/patch',
// './src/index.tsx'
// ],
// modulesToExclude: ['my-style']
// }
const vendorModulesMinusExclusions = vendorDependencies.filter(vendorModule =>
config.mainModules.indexOf(vendorModule) === -1 && config.modulesToExclude.indexOf(vendorModule) === -1);

return vendorModulesMinusExclusions;
}

exports.makeVendorEntry = makeVendorEntry;
138 changes: 138 additions & 0 deletions examples/hot/internal/webpack/webpack.development.config.js
@@ -0,0 +1,138 @@
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const ForkTsCheckerNotifierWebpackPlugin = require('fork-ts-checker-notifier-webpack-plugin');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

// * Only necessary until https://github.com/Realytics/fork-ts-checker-webpack-plugin/pull/48 has been merged and released
// START
const chalk = require("chalk");
const os = require("os");

function formatterForLineAndColumnUrlClicking(message, useColors) {
const colors = new chalk.constructor({ enabled: useColors });
const messageColor = message.isWarningSeverity() ? colors.bold.yellow : colors.bold.red;
const fileAndNumberColor = colors.bold.cyan;
const codeColor = colors.grey;

return [
messageColor(message.getSeverity().toUpperCase() + " in ") +
fileAndNumberColor(message.getFile() + "(" + message.getLine() + "," + message.getCharacter() + ")") +
messageColor(':'),
codeColor(message.getFormattedCode() + ': ') + message.getContent()
].join(os.EOL);
}
// END

const shared = require('./shared');
const main = [
'core-js',
'whatwg-fetch',
'react-hot-loader/patch',
'./src/index.tsx'
];
const vendor = shared.makeVendorEntry({ mainModules: main, modulesToExclude: ['semantic-ui-css'] })

module.exports = {
context: process.cwd(), // to automatically find tsconfig.json
entry: {
main: main,
vendor: vendor
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
publicPath: "/"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.js' }),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new ForkTsCheckerNotifierWebpackPlugin({ title: 'TypeScript', excludeWarnings: false }),
new ForkTsCheckerWebpackPlugin({
tslint: true,
checkSyntacticErrors: true,
formatter: formatterForLineAndColumnUrlClicking,
watch: ['./src'] // optional but improves performance (fewer stat calls)
}),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
}),
new HtmlWebpackPlugin({
inject: true,
template: 'src/index.html'
}),
],
module: {
rules: [
{
test: /.tsx?$/,
use: [
{ loader: 'react-hot-loader/webpack' },
{ loader: 'cache-loader' },
{
loader: 'thread-loader',
options: {
// there should be 1 cpu for the fork-ts-checker-webpack-plugin
workers: require('os').cpus().length - 1,
},
},
{ loader: 'ts-loader', options: { happyPackMode: true, silent: true } }
],
exclude: path.resolve(process.cwd(), 'node_modules'),
include: path.resolve(process.cwd(), "src"),
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: false,
camelCase: true,
importLoaders: 2
}
},
{ loader: 'resolve-url-loader' },
{ loader: "sass-loader?sourceMap" }
]
},
{
test: /\.svg/,
use: {
loader: 'svg-url-loader',
options: {
noquotes: false
}
}
},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
},
]
},
{
test: /\.jpe?g$|\.ico$|\.gif$|\.png$|\.svg$|\.woff$|\.woff2$|\.eot$|\.ttf$|\.wav$|\.mp3$/,
loader: 'file-loader?name=[name].[hash].[ext]'
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
devtool: 'inline-source-map',
devServer: {
clientLogLevel: 'warning',
open: true,
hot: true,
historyApiFallback: true,
stats: 'errors-only'
}
};
120 changes: 120 additions & 0 deletions examples/hot/internal/webpack/webpack.production.config.js
@@ -0,0 +1,120 @@
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const shared = require('./shared');
const main = [
'core-js',
'whatwg-fetch',
'./src/index.tsx'
];
const vendor = shared.makeVendorEntry({ mainModules: main, modulesToExclude: ['semantic-ui-css'] })

module.exports = {
context: process.cwd(), // to automatically find tsconfig.json
entry: {
main: main,
vendor: vendor
},
output: {
path: path.join(process.cwd(), 'dist'),
filename: '[name].js',
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.js' }),
new ForkTsCheckerWebpackPlugin({
async: false,
memoryLimit: 4096,
checkSyntacticErrors: true
}),
new webpack.NoEmitOnErrorsPlugin(),
new UglifyJSPlugin(/*{
unused: true,
dead_code: true
}*/),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
new HtmlWebpackPlugin({
hash: true,
inject: true,
template: 'src/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
],
module: {
rules: [
{
test: /.tsx?$/,
use: [
{ loader: 'cache-loader' },
{
loader: 'thread-loader',
options: {
// there should be 1 cpu for the fork-ts-checker-webpack-plugin
workers: require('os').cpus().length - 1,
},
},
{ loader: 'ts-loader', options: { happyPackMode: true } }
],
exclude: /node_modules/
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: false,
camelCase: true,
importLoaders: 2,
minimize: true
}
},
{ loader: 'resolve-url-loader' },
{ loader: "sass-loader?sourceMap" }
]
},
{
test: /\.svg/,
use: {
loader: 'svg-url-loader',
options: {
noquotes: false
}
}
},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
},
]
},
{
test: /\.jpe?g$|\.ico$|\.gif$|\.png$|\.svg$|\.woff$|\.woff2$|\.eot$|\.ttf$|\.wav$|\.mp3$/,
loader: 'file-loader?name=[name].[hash].[ext]'
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
}
};

0 comments on commit 2e2f29a

Please sign in to comment.