Add TypeScript, generate stations and a line

This commit is contained in:
Tyler Hallada 2018-04-05 22:41:19 -04:00
parent 434578cebc
commit edae3f76f4
12 changed files with 430 additions and 37 deletions

185
package-lock.json generated
View File

@ -375,6 +375,17 @@
"@babel/plugin-syntax-async-generators": "7.0.0-beta.42" "@babel/plugin-syntax-async-generators": "7.0.0-beta.42"
} }
}, },
"@babel/plugin-proposal-class-properties": {
"version": "7.0.0-beta.42",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.0.0-beta.42.tgz",
"integrity": "sha512-VXRmo/t2nAVciXxEgPTAfcUBXj0UXNPIvX2aj3lzHL51N+uh+rtgsIF0nuZwGE4u89WvBDH66yjAu60Ra674kw==",
"dev": true,
"requires": {
"@babel/helper-function-name": "7.0.0-beta.42",
"@babel/helper-plugin-utils": "7.0.0-beta.42",
"@babel/plugin-syntax-class-properties": "7.0.0-beta.42"
}
},
"@babel/plugin-proposal-object-rest-spread": { "@babel/plugin-proposal-object-rest-spread": {
"version": "7.0.0-beta.42", "version": "7.0.0-beta.42",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0-beta.42.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0-beta.42.tgz",
@ -446,6 +457,15 @@
"@babel/helper-plugin-utils": "7.0.0-beta.42" "@babel/helper-plugin-utils": "7.0.0-beta.42"
} }
}, },
"@babel/plugin-syntax-class-properties": {
"version": "7.0.0-beta.42",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.0.0-beta.42.tgz",
"integrity": "sha512-nG0XCeuni6GgjxOqtxVtnfSoRFeXdqY6cja83cmFpC1klw8f6XShbeDmK7xX1mUYBHkEqLTDurlX+fuua9siCg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "7.0.0-beta.42"
}
},
"@babel/plugin-syntax-object-rest-spread": { "@babel/plugin-syntax-object-rest-spread": {
"version": "7.0.0-beta.42", "version": "7.0.0-beta.42",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0-beta.42.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0-beta.42.tgz",
@ -927,12 +947,39 @@
} }
} }
}, },
"@fimbul/bifrost": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@fimbul/bifrost/-/bifrost-0.6.0.tgz",
"integrity": "sha512-BJ19rjnFFCeopEhbyK2Chg3Tq+o5xkjd6dtKxmFhfjwLH1Il2G7Ha4Jel2hpbyZL2Fh9/vrM9U0bpkANAL3pjA==",
"dev": true,
"requires": {
"@fimbul/ymir": "0.6.0",
"get-caller-file": "1.0.2",
"tslib": "1.9.0"
}
},
"@fimbul/ymir": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@fimbul/ymir/-/ymir-0.6.0.tgz",
"integrity": "sha512-iyh/8OiZlzjlPytdjdodA86d38YtRL0sSAx169SMgqP4dsouH2rtctf4Nrg4FYvWoG0e9y9XT3iWL+mjTgYNRw==",
"dev": true,
"requires": {
"inversify": "4.11.1",
"reflect-metadata": "0.1.12",
"tslib": "1.9.0"
}
},
"@sindresorhus/is": { "@sindresorhus/is": {
"version": "0.7.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
"integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==",
"dev": true "dev": true
}, },
"@types/pixi.js": {
"version": "4.7.2",
"resolved": "https://registry.npmjs.org/@types/pixi.js/-/pixi.js-4.7.2.tgz",
"integrity": "sha512-ybrqVdncNCa81fCYCqxz/CISyMbXl8usszNv0mwdeYDyfDqmemQHJtf4GtduHva+3suhItPc9Akr/WfV19zWiQ=="
},
"accepts": { "accepts": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
@ -6801,6 +6848,12 @@
"loose-envify": "1.3.1" "loose-envify": "1.3.1"
} }
}, },
"inversify": {
"version": "4.11.1",
"resolved": "https://registry.npmjs.org/inversify/-/inversify-4.11.1.tgz",
"integrity": "sha512-9bs/36crPdTSOCcoomHMb96s+B8W0+2c9dHFP/Srv9ZQaPnUvsMgzmMHfgVECqfHVUIW+M5S7SYOjoig8khWuQ==",
"dev": true
},
"invert-kv": { "invert-kv": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
@ -10156,6 +10209,12 @@
} }
} }
}, },
"reflect-metadata": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.12.tgz",
"integrity": "sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==",
"dev": true
},
"regenerate": { "regenerate": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz",
@ -11509,6 +11568,126 @@
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
"dev": true "dev": true
}, },
"ts-loader": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-4.1.0.tgz",
"integrity": "sha512-R4VEE0SZhU8gLa9Aayg2XOvpVjXtbB7KMLXs4He0xr92DM5G12i76IWd+lMLfmCz66Ztr2XFvDNvMAymHJGIqg==",
"dev": true,
"requires": {
"chalk": "2.3.2",
"enhanced-resolve": "4.0.0",
"loader-utils": "1.1.0",
"micromatch": "3.1.10",
"semver": "5.5.0"
}
},
"tslib": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz",
"integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==",
"dev": true
},
"tslint": {
"version": "5.9.1",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz",
"integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=",
"dev": true,
"requires": {
"babel-code-frame": "6.26.0",
"builtin-modules": "1.1.1",
"chalk": "2.3.2",
"commander": "2.13.0",
"diff": "3.5.0",
"glob": "7.1.2",
"js-yaml": "3.11.0",
"minimatch": "3.0.4",
"resolve": "1.6.0",
"semver": "5.5.0",
"tslib": "1.9.0",
"tsutils": "2.25.0"
}
},
"tslint-config-airbnb": {
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/tslint-config-airbnb/-/tslint-config-airbnb-5.8.0.tgz",
"integrity": "sha512-4fTcxL/3Xbct8BIt1jjZvp9EavqwUO7ND9mpRsdHmvdAYGCbGdaIaUg9NCB6VXLDtTBTR5XT/tEU3/jBN/JPAw==",
"dev": true,
"requires": {
"tslint-consistent-codestyle": "1.13.0",
"tslint-eslint-rules": "4.1.1",
"tslint-microsoft-contrib": "5.0.3"
}
},
"tslint-consistent-codestyle": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/tslint-consistent-codestyle/-/tslint-consistent-codestyle-1.13.0.tgz",
"integrity": "sha512-7fcstphFz9Rw2+SAe32VjtnQEHYEQVSGgEOea9hN/8JMJQGpGkxvVbqxhsXew9vkRtvPQuoj1pQoZ5Eadp4B6A==",
"dev": true,
"requires": {
"@fimbul/bifrost": "0.6.0",
"tslib": "1.9.0",
"tsutils": "2.25.0"
}
},
"tslint-eslint-rules": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/tslint-eslint-rules/-/tslint-eslint-rules-4.1.1.tgz",
"integrity": "sha1-fDDniC8mvCdr/5HSOEl1xp2viLo=",
"dev": true,
"requires": {
"doctrine": "0.7.2",
"tslib": "1.9.0",
"tsutils": "1.9.1"
},
"dependencies": {
"doctrine": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz",
"integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=",
"dev": true,
"requires": {
"esutils": "1.1.6",
"isarray": "0.0.1"
}
},
"esutils": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz",
"integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=",
"dev": true
},
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
"dev": true
},
"tsutils": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-1.9.1.tgz",
"integrity": "sha1-ufmrROVa+WgYMdXyjQrur1x1DLA=",
"dev": true
}
}
},
"tslint-microsoft-contrib": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/tslint-microsoft-contrib/-/tslint-microsoft-contrib-5.0.3.tgz",
"integrity": "sha512-5AnfTGlfpUzpRHLmoojPBKFTTmbjnwgdaTHMdllausa4GBPya5u36i9ddrTX4PhetGZvd4JUYIpAmgHqVnsctg==",
"dev": true,
"requires": {
"tsutils": "2.25.0"
}
},
"tsutils": {
"version": "2.25.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.25.0.tgz",
"integrity": "sha512-SPgUlOAUAe6fCyPi0QR4U0jRuDsHHKvzIR6/hHd0YR0bb8MzeLJgCagkPSmZeJjWImnpJ0xq6XHa9goTvMBBCQ==",
"dev": true,
"requires": {
"tslib": "1.9.0"
}
},
"tty-browserify": { "tty-browserify": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
@ -11540,6 +11719,12 @@
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true "dev": true
}, },
"typescript": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.1.tgz",
"integrity": "sha512-Ao/f6d/4EPLq0YwzsQz8iXflezpTkQzqAyenTiw4kCUGr1uPiFLC3+fZ+gMZz6eeI/qdRUqvC+HxIJzUAzEFdg==",
"dev": true
},
"uglify-es": { "uglify-es": {
"version": "3.3.9", "version": "3.3.9",
"resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",

View File

@ -7,7 +7,7 @@
"start": "NODE_ENV=development ./node_modules/.bin/webpack-dev-server --mode development", "start": "NODE_ENV=development ./node_modules/.bin/webpack-dev-server --mode development",
"build": "NODE_ENV=production ./node_modules/.bin/webpack --mode production", "build": "NODE_ENV=production ./node_modules/.bin/webpack --mode production",
"deploy": "./node_modules/.bin/gh-pages -d dist", "deploy": "./node_modules/.bin/gh-pages -d dist",
"lint": "./node_modules/.bin/eslint src/", "lint": "./node_modules/.bin/tslint src/",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"repository": { "repository": {
@ -18,6 +18,8 @@
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.0.0-beta.42", "@babel/core": "^7.0.0-beta.42",
"@babel/plugin-proposal-class-properties": "^7.0.0-beta.42",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.42",
"@babel/preset-env": "^7.0.0-beta.42", "@babel/preset-env": "^7.0.0-beta.42",
"babel-loader": "^8.0.0-beta.2", "babel-loader": "^8.0.0-beta.2",
"css-loader": "^0.28.11", "css-loader": "^0.28.11",
@ -31,11 +33,16 @@
"gh-pages": "^1.1.0", "gh-pages": "^1.1.0",
"html-webpack-plugin": "^3.1.0", "html-webpack-plugin": "^3.1.0",
"style-loader": "^0.20.3", "style-loader": "^0.20.3",
"ts-loader": "^4.1.0",
"tslint": "^5.9.1",
"tslint-config-airbnb": "^5.8.0",
"typescript": "^2.8.1",
"webpack": "^4.4.1", "webpack": "^4.4.1",
"webpack-cli": "^2.0.13", "webpack-cli": "^2.0.13",
"webpack-dev-server": "^3.1.1" "webpack-dev-server": "^3.1.1"
}, },
"dependencies": { "dependencies": {
"@types/pixi.js": "^4.7.2",
"pixi.js": "^4.7.1" "pixi.js": "^4.7.1"
} }
} }

42
src/Line.ts Normal file
View File

@ -0,0 +1,42 @@
import Station from './Station';
import { distance, randomInt, randomPoint } from './utils';
const largestStation = (stations: Station[]): Station => {
let largest: Station = null;
for (const station of stations) {
if (largest === null || station.population > largest.population) {
largest = station;
}
}
return largest;
};
const stationsWithinRadius = (stations: Station[], point: PIXI.Point,
radius: number): Station[] => (
stations.filter(station => distance(point, station.location) <= radius)
);
const closestStations = (stations: Station[], point: PIXI.Point, num: number): Station[] => {
// bleh, i'm done
return stations;
};
export default class Line {
public stations: Station[];
constructor(stations: Station[], numStations: number) {
this.stations = [];
let stationsLeft = stations;
let largest = largestStation(stationsLeft);
stationsLeft = stationsLeft.filter(s => s !== largest);
this.stations.push(largest);
while (this.stations.length < numStations) {
largest = largestStation(stationsWithinRadius(stationsLeft, largest.location, 500));
if (largest === null) {
break;
}
stationsLeft = stationsLeft.filter(s => s !== largest);
this.stations.push(largest);
}
}
}

11
src/Station.ts Normal file
View File

@ -0,0 +1,11 @@
export default class Station {
public location: PIXI.Point;
public population: number;
public connections: Station[];
constructor(location: PIXI.Point, population: number, connections?: Station[]) {
this.location = location;
this.population = population;
this.connections = connections;
}
}

23
src/Train.ts Normal file
View File

@ -0,0 +1,23 @@
import Station from './Station';
export default class Train {
public location: PIXI.Point;
public speed: number;
public origin: Station;
public destination: Station;
public passengers: number;
constructor(location: PIXI.Point, speed: number, passengers: number, origin: Station,
destination: Station) {
this.location = location;
this.speed = speed;
this.origin = origin;
this.destination = destination;
this.passengers = passengers;
}
public boardPassengers() {
if (this.location === this.origin.location) { // about to leave a station
}
}
}

View File

@ -1,30 +0,0 @@
import * as PIXI from 'pixi.js';
import { randomInt } from './utils';
import './style.css';
const app = new PIXI.Application(window.innerWidth, window.innerHeight);
const ticker = new PIXI.ticker.Ticker();
const graphics = new PIXI.Graphics();
const fpsText = new PIXI.Text('', { fontSize: '25px', fontFamily: 'monospace', fill: 'yellow' });
fpsText.anchor = new PIXI.Point(1, 0);
fpsText.x = window.innerWidth - 1;
fpsText.y = 0;
ticker.stop();
ticker.add((deltaTime) => {
fpsText.setText(Math.round(ticker.FPS));
graphics.lineStyle(1, 0xaeaeae, 1);
graphics.moveTo(randomInt(9, window.innerWidth), randomInt(0, window.innerHeight));
graphics.lineTo(randomInt(9, window.innerWidth), randomInt(0, window.innerHeight));
});
ticker.start();
app.stage.addChild(graphics);
app.stage.addChild(fpsText);
document.body.appendChild(app.view);
window.addEventListener('resize', () => {
app.renderer.resize(window.innerWidth, window.innerHeight);
});

106
src/transport.ts Normal file
View File

@ -0,0 +1,106 @@
import * as PIXI from 'pixi.js';
import Line from './Line';
import Station from './Station';
import Train from './Train';
import { distance, randomInt, randomPoint } from './utils';
import './style.css';
const isPointDistant = (point: PIXI.Point, stations: Station[], minDistance: number): boolean => {
for (const station of stations) {
if (distance(point, station.location) < minDistance) {
return false;
}
}
return true;
};
const randomDistantPoint = (stations: Station[], minDistance: number): PIXI.Point | null => {
let tries = 100;
while (tries > 0) {
const point = randomPoint();
if (isPointDistant(point, stations, minDistance)) {
return point;
}
tries -= 1;
}
return null;
};
const initStations = (numStations: number): Station[] => {
const stations: Station[] = [];
for (let i = 0; i < numStations; i += 1) {
stations.push(new Station(randomDistantPoint(stations, 30), randomInt(100, 1000)));
}
return stations;
};
const drawStations = (stations: Station[], graphics: PIXI.Graphics) => {
for (const station of stations) {
graphics.drawCircle(station.location.x, station.location.y, station.population / 60);
}
};
const initTrains = (numTrains: number, stations: Station[]): Train[] => {
const trains = [];
for (let i = 0; i < numTrains; i += 1) {
const originStation = stations[Math.floor(Math.random() * stations.length)];
const destStation = stations[Math.floor(Math.random() * stations.length)];
trains.push(new Train(originStation.location, 0, 0, originStation, destStation));
}
return trains;
};
const drawLine = (line: Line, graphics: PIXI.Graphics) => {
const start = line.stations[0].location;
graphics.moveTo(start.x, start.y);
for (const station of line.stations.slice(1)) {
graphics.lineTo(station.location.x, station.location.y);
}
};
const run = () => {
const app = new PIXI.Application({
antialias: true,
height: window.innerHeight,
width: window.innerWidth,
});
const ticker = new PIXI.ticker.Ticker();
const graphics = new PIXI.Graphics();
const fpsText = new PIXI.Text('', { fontSize: '25px', fontFamily: 'monospace', fill: 'yellow' });
fpsText.anchor = new PIXI.ObservablePoint(null, 0, 1);
fpsText.x = window.innerWidth;
fpsText.y = 0;
// make these const
let stations = initStations(30);
let trains = initTrains(15, stations);
let line = new Line(stations, 10);
stations = initStations(30);
trains = initTrains(15, stations);
line = new Line(stations, 10);
ticker.stop();
ticker.add((deltaTime) => {
graphics.clear();
fpsText.text = `${Math.round(ticker.FPS)}`;
graphics.lineStyle(1, 0xaeaeae, 1);
drawStations(stations, graphics);
drawLine(line, graphics);
});
ticker.start();
app.stage.addChild(graphics);
app.stage.addChild(fpsText);
document.body.appendChild(app.view);
window.addEventListener('resize', () => {
app.renderer.resize(window.innerWidth, window.innerHeight);
});
};
run();

View File

@ -1,4 +0,0 @@
export const randomInt = (min, max) => (
// inclusive of min and max
Math.floor(Math.random() * (max - (min + 1))) + min
);

16
src/utils.ts Normal file
View File

@ -0,0 +1,16 @@
import * as PIXI from 'pixi.js';
export const randomInt = (min: number, max: number): number => (
// inclusive of min and max
Math.floor(Math.random() * (max - (min + 1))) + min
);
export const randomPoint = () => (
new PIXI.Point(randomInt(0, window.innerWidth), randomInt(0, window.innerHeight))
);
export const distance = (pointA: PIXI.Point, pointB: PIXI.Point): number => {
const distX = pointA.x - pointB.x;
const distY = pointA.y - pointB.y;
return Math.sqrt((distX * distX) + (distY * distY));
};

11
tsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"jsx": "react",
"allowJs": true
}
}

11
tslint.json Normal file
View File

@ -0,0 +1,11 @@
{
"defaultSeverity": "error",
"extends": [
"tslint:recommended",
"tslint-config-airbnb",
"tslint-eslint-rules"
],
"jsRules": {},
"rules": {},
"rulesDirectory": []
}

View File

@ -5,7 +5,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
const env = process.env.NODE_ENV; const env = process.env.NODE_ENV;
module.exports = { module.exports = {
entry: './src/transport.js', entry: './src/transport.ts',
output: { output: {
filename: 'transport.js', filename: 'transport.js',
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
@ -18,10 +18,22 @@ module.exports = {
use: { use: {
loader: 'babel-loader', loader: 'babel-loader',
options: { options: {
presets: ['@babel/preset-env'], presets: [
'@babel/preset-env',
],
plugins: [
'@babel/proposal-class-properties',
'@babel/proposal-object-rest-spread',
],
cacheDirectory: env === 'development',
}, },
}, },
}, },
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{ {
test: /\.css$/, test: /\.css$/,
use: env === 'production' use: env === 'production'
@ -33,6 +45,9 @@ module.exports = {
}, },
], ],
}, },
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [ plugins: [
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: path.join(__dirname, 'index.html'), template: path.join(__dirname, 'index.html'),