1
0
Fork 0
This commit is contained in:
ChaotiCryptidz 2022-05-31 22:00:53 +01:00
commit bdc7036d8d
No known key found for this signature in database
16 changed files with 800 additions and 0 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use nix

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
node_modules
package-lock.json
dist
.eslintcache
result

12
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,12 @@
pages:
stage: deploy
image: docker.io/library/alpine:edge
script:
- apk add nodejs npm git
- npm install --save-dev
- npx webpack
- mv dist public
- cp _redirects public
artifacts:
paths:
- public

26
package.json Normal file
View file

@ -0,0 +1,26 @@
{
"name": "food",
"version": "latest",
"devDependencies": {
"css-loader": "^6.7.1",
"css-minimizer-webpack-plugin": "^4.0.0",
"html-webpack-plugin": "^5.5.0",
"node-sass": "^7.0.1",
"prettier": "^2.6.2",
"sass-loader": "^13.0.0",
"ts-loader": "^9.3.0",
"typescript": "^4.7.2",
"webpack": "^5.72.1",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.0"
},
"dependencies": {
"@fontsource/comic-neue": "^4.5.8",
"@fontsource/opendyslexic": "^4.5.4",
"bootstrap": "latest",
"normalize.css": "^8.0.1",
"postcss-loader": "^7.0.0",
"preact": "^10.7.2",
"style-loader": "^3.3.1"
}
}

5
shell.nix Normal file
View file

@ -0,0 +1,5 @@
{ pkgs ? import <nixpkgs> { } }: pkgs.mkShell {
packages = with pkgs; [
nodejs
];
}

0
src/defaults.tsx Normal file
View file

69
src/foodItems.tsx Normal file
View file

@ -0,0 +1,69 @@
import { Component, JSX } from "preact"
import { FoodExcludeTypes } from "./types";
export const FoodItemsContainer = (props: {
children: JSX.Element | JSX.Element[] | null
title: string,
}): JSX.Element => {
return (
<div>
<h3>{props.title}</h3>
<div class="list-group">
{props.children}
</div>
</div>
);
}
function shouldShowItem(contents, exclude: FoodExcludeTypes): boolean {
if (!exclude) return false;
for (let key of Object.keys(exclude)) {
if (Object.keys(contents).includes(key)) {
if (!exclude[key]) return false;
}
}
return true;
}
type BaseFoodItemProps = {
contents?: Partial<FoodExcludeTypes>,
exclude?: FoodExcludeTypes,
}
const HideIfFoodExcluded = (props: BaseFoodItemProps & { children: JSX.Element }) => {
if (!props.contents) {
return props.children;
} else if (shouldShowItem(props.contents, props.exclude)) {
return props.children;
} else {
return <></>;
}
}
type FoodItemProps = BaseFoodItemProps & {
title: string,
};
export class FoodItem extends Component<FoodItemProps> {
render() {
return (
<HideIfFoodExcluded {...this.props}>
<li class="list-group-item">{this.props.title}</li>
</HideIfFoodExcluded>
)
}
}
export class AdvancedFoodItem extends Component<FoodItemProps & { extra: string }> {
render() {
return (
<HideIfFoodExcluded {...this.props}>
<div class="list-group-item">
<h5 class="mb-1">{this.props.title}</h5>
<p class="mb-1">{this.props.extra}</p>
</div>
</HideIfFoodExcluded>
)
}
}

179
src/foodTypeToggles.tsx Normal file
View file

@ -0,0 +1,179 @@
import { Component, createRef, JSX, RefObject } from "preact";
import { ToggleableBox } from "./toggleableBox";
import { FoodExcludeTypes } from "./types";
let defaultBroadExclusions = {
isVegan: false,
isVegetarian: false,
}
let defaultFoodToggles: FoodExcludeTypes = {
containsMeat: true,
containsFish: true,
containsEggs: true,
containsMilk: true,
containsAlcohol: true,
}
export class FoodTypeToggles extends Component<{
onChange?: (toggles: FoodExcludeTypes) => void;
}, {
toggles: FoodExcludeTypes;
broadExclusions: {
isVegan: boolean;
isVegetarian: boolean;
}
}> {
refs = {
"isVegan": createRef<ToggleableBox>(),
"isVegetarian": createRef<ToggleableBox>(),
"containsMeat": createRef<ToggleableBox>(),
"containsFish": createRef<ToggleableBox>(),
"containsEggs": createRef<ToggleableBox>(),
"containsMilk": createRef<ToggleableBox>(),
"containsAlcohol": createRef<ToggleableBox>(),
}
constructor() {
super()
this.state = {
toggles: { ...defaultFoodToggles },
broadExclusions: defaultBroadExclusions,
}
}
componentDidMount(): void {
this.setToDefaults();
this.sendChangedEvent();
}
setCheckedStateOfInputBoxes(names: string[], value: boolean) {
for (let name of names) {
if (Object.keys(this.refs).includes(name)) {
let ref: RefObject<ToggleableBox> = this.refs[name];
if (ref.current) {
if (Object.keys(this.state.toggles).includes(name)) {
this.state.toggles[name] = value;
}
ref.current.forceChange(value)
} else {
console.debug(`Can't get current ref for: ${name}`)
}
} else {
console.debug(`Can't find ref for ${name}`)
}
}
}
veganModeEnable() {
this.vegetarianModeEnable()
this.setCheckedStateOfInputBoxes(["containsMilk", "containsEggs"], false);
}
vegetarianModeEnable() {
this.setCheckedStateOfInputBoxes(["containsMeat", "containsFish"], false);
}
veganModeDisable() {
this.setCheckedStateOfInputBoxes(["isVegan"], false);
}
vegetarianModeDisable() {
this.setCheckedStateOfInputBoxes(["isVegetarian"], false);
}
setToDefaults() {
for (let toggle of Object.keys(defaultBroadExclusions)) {
console.debug(`Setting broad exclusion ${toggle} to ${defaultBroadExclusions[toggle]}`)
this.setCheckedStateOfInputBoxes([toggle], defaultBroadExclusions[toggle])
}
for (let toggle of Object.keys(defaultFoodToggles)) {
console.debug(`Setting food default of ${toggle} to ${defaultFoodToggles[toggle]}`)
console.debug(defaultFoodToggles)
this.setCheckedStateOfInputBoxes([toggle], defaultFoodToggles[toggle])
}
}
sendChangedEvent() {
console.debug(`Changed state of food type toggles`, this.state.toggles)
if(this.props.onChange) this.props.onChange(this.state.toggles);
}
render(): JSX.Element {
return (
<div>
<h3 class="mt-5">Toggles</h3>
<div>
<p>Broad Toggles</p>
<ToggleableBox
title="Vegan" id="isVegan"
checked={defaultBroadExclusions.isVegan}
ref={this.refs.isVegan} onChange={(isVegan: boolean) => {
if (isVegan) this.veganModeEnable();
this.sendChangedEvent();
}} />
<ToggleableBox
title="Vegetarian (ovo-lacto vegetarian)" id="isVegetarian"
checked={defaultBroadExclusions.isVegetarian}
ref={this.refs.isVegetarian} onChange={(isVegetarian: boolean) => {
if (isVegetarian) this.vegetarianModeEnable();
this.sendChangedEvent();
}} />
<p>Specific Toggles</p>
<ToggleableBox
title="Meat" id="containsMeat"
checked={defaultFoodToggles.containsMeat}
ref={this.refs.containsMeat} onChange={(containsMeat: boolean) => {
this.state.toggles.containsMeat = containsMeat;
if (containsMeat) {
this.veganModeDisable();
this.vegetarianModeDisable();
}
this.sendChangedEvent();
}} />
<ToggleableBox
title="Fish" id="containsFish"
checked={defaultFoodToggles.containsFish}
ref={this.refs.containsFish} onChange={(containsFish: boolean) => {
this.state.toggles.containsFish = containsFish;
if (containsFish) {
this.veganModeDisable();
this.vegetarianModeDisable();
}
this.sendChangedEvent();
}} />
<ToggleableBox
title="Eggs" id="containsEggs"
checked={defaultFoodToggles.containsEggs}
ref={this.refs.containsEggs} onChange={(containsEggs: boolean) => {
this.state.toggles.containsEggs = containsEggs;
if (containsEggs) this.veganModeDisable();
this.sendChangedEvent();
}} />
<ToggleableBox
title="Milk" id="containsMilk"
checked={defaultFoodToggles.containsMilk}
ref={this.refs.containsMilk} onChange={(containsMilk: boolean) => {
this.state.toggles.containsMilk = containsMilk;
if (containsMilk) this.veganModeDisable();
this.sendChangedEvent();
}} />
<ToggleableBox
title="Alcohol" id="containsAlcohol"
checked={defaultFoodToggles.containsAlcohol}
ref={this.refs.containsAlcohol} onChange={(containsAlcohol: boolean) => {
this.state.toggles.containsAlcohol = containsAlcohol;
this.sendChangedEvent();
}} />
<button type="button mt-5" class="btn btn-danger" onClick={() => {
this.setToDefaults();
this.sendChangedEvent();
}}>Reset</button>
</div>
</div>
);
}
}

21
src/main.tsx Normal file
View file

@ -0,0 +1,21 @@
import { render } from "preact";
import { MainPage } from "./mainPage";
import "./theme.scss";
document.addEventListener(
"DOMContentLoaded",
async () => {
render(
<>
<main role="main" class="container">
<MainPage />
</main>
<footer class="footer">
<div class="container">
<span class="text-muted">[Screaming]</span>
</div>
</footer>
</>, document.body);
}
);

187
src/mainPage.tsx Normal file
View file

@ -0,0 +1,187 @@
import { Component, createRef } from "preact";
import { AdvancedFoodItem, FoodItem, FoodItemsContainer } from "./foodItems";
import { FoodTypeToggles } from "./foodTypeToggles";
import { FoodExcludeTypes } from "./types";
const FONT_TYPES = [
["default", "Default (Comic Sans, Comic Neue or Default)"],
["comicneue", "Comic Neue"],
["opendyslexic", "Open Dyslexic"]
];
export class SettingsBlock extends Component {
constructor() {
super()
}
fontSettingSelectRef = createRef<HTMLSelectElement>()
onFontChange() {
if (!this.fontSettingSelectRef.current) return;
let newFont = this.fontSettingSelectRef.current.value;
console.log(newFont);
for (let font of FONT_TYPES) {
document.body.removeAttribute(`data-font-${font[1]}`)
}
document.body.setAttribute("data-font", newFont);
}
render() {
return <div>
<h3>Settings</h3>
<div class="form-group">
<label for="fontSettingSelect">Font</label>
<select ref={this.fontSettingSelectRef} class="form-control" id="fontSettingSelect" onChange={() => this.onFontChange()}>
{...FONT_TYPES.map((font: string[]) => {
console.log(`FONT: ${font}`)
return <option value={font[0]}>{font[1]}</option>;
})}
</select>
</div>
</div>
}
}
export class MainPage extends Component<unknown, { toggles: FoodExcludeTypes }> {
constructor() {
super()
}
render() {
return <>
<h1 class="mt-5">Chaos's Food Likes/Dislikes</h1>
<p class="lead">a hopefully helpful guide on what food we like?</p>
<SettingsBlock />
<FoodTypeToggles onChange={(toggles) => {
this.setState({ toggles });
}} />
<br />
<FoodItemsContainer title="Drinks">
<FoodItem title="Chocolate flavor Soymilk" />
<FoodItem title="Pineapple Juice" />
<FoodItem title="Mango Juice" />
<FoodItem title="Pineapple Juice" />
<FoodItem title="Yogurt-like drinks" />
<FoodItem title="Lactose Free Chocolate Milk" contents={{ containsMilk: true }} exclude={this.state.toggles} />
<AdvancedFoodItem title="Caffeinated Energy Drinks" extra={"Brands such as Monster Energy & Red Bull"} />
<AdvancedFoodItem
title="Squash/Cordial/Fruit Juice Concentrate"
extra={"Flavors such as \"Apple&Blackcurrent\", \"Blackcurrent\", \"Orange\" "}
/>
<AdvancedFoodItem
title="Fruity Alcoholic Ciders"
extra="Has to be quite sugary and not at all bitter"
contents={{ containsAlcohol: true }} exclude={this.state.toggles}
/>
<AdvancedFoodItem
title="Vodka-based Cocktails"
extra="Good when sweet and fruity; do not like when too bitter"
contents={{ containsAlcohol: true }} exclude={this.state.toggles}
/>
</FoodItemsContainer>
<br />
<FoodItemsContainer title="Snacks">
<AdvancedFoodItem title="Chips" extra={"Also known as crisps; Flavors such as salted & sweet chilli are recommended"} />
<AdvancedFoodItem title="Pringles" extra={"Salted; or also any other brand of Hyperbolic Paraboloid shaped potato snacks"} />
<FoodItem title="Beef/Pork Jerky" contents={{ containsMeat: true }} exclude={this.state.toggles} />
<AdvancedFoodItem title="Hummus" extra="For dipping of carrots and chips" />
<AdvancedFoodItem title="Wheat/Starch-Coated Chilli Peanuts" extra="Not a fan of peanuts on own; but ok when coated" />
<FoodItem title="Whole or Sliced Firm Cucumber" />
<FoodItem title="Sliced or Sticks of Carrots" />
<FoodItem title="Sweetcorn" />
<FoodItem title="Firm Pickles" />
</FoodItemsContainer>
<br />
<FoodItemsContainer title="Treats">
<AdvancedFoodItem title="Sugary Sweets" extra={"Preferably ones not too acidic"} />
<AdvancedFoodItem title="Doughnuts" extra={"Circle shape with hole in middle; glazed good but not too much of it; NOT jam filled ones"} />
<AdvancedFoodItem title="Yum-Yums" extra={"A kind of twisted doughnut dough covered in sugary glaze"} />
<AdvancedFoodItem title="Chocolate" extra={"Light chocolate only; Can't be too bitter"} />
<FoodItem title="Skittles" />
</FoodItemsContainer>
<br />
<FoodItemsContainer title="Smaller Foods">
<FoodItem title="Chicken Nuggets" contents={{ containsMeat: true }} exclude={this.state.toggles} />
<FoodItem title="Turkey Dinos" contents={{ containsMeat: true }} exclude={this.state.toggles} />
<FoodItem title="Smile or Waffle shaped formed potato" />
<FoodItem title="Fish Fingers" contents={{ containsFish: true }} exclude={this.state.toggles} />
<AdvancedFoodItem title="Veggie Dippers" extra="As long as don't contain sensory bads; McDonalds kind are good" />
<AdvancedFoodItem title="Falafel Wraps" extra={"Great with hummus&cucumber"} />
<FoodItem title="Scrambled Eggs" contents={{ containsEggs: true }} exclude={this.state.toggles} />
<FoodItem title="French Fries" />
</FoodItemsContainer>
<br />
<FoodItemsContainer title="Larger Foods">
<FoodItem title="Garlic Bread!!!!!!!!!!!! So Good!!!" />
<FoodItem title="Pizza" contents={{ containsMilk: true }} exclude={this.state.toggles} />
<FoodItem title="Pasta" />
<FoodItem title="Spongy Fried Battered Tofu" />
<FoodItem title="Rice or Cooked Grains" />
<FoodItem title="Roast Potatos" />
<FoodItem title="Baked Potatos" />
<FoodItem title={"Fried Egg & French Fries"} contents={{ containsEggs: true }} exclude={this.state.toggles} />
<FoodItem title="Omlette" contents={{ containsEggs: true }} exclude={this.state.toggles} />
<FoodItem title={"Cooked Potato with Spinach & Turmeric (Saag Aloo?)"} />
<FoodItem title={"Pasta & Meatballs"} contents={{ containsMeat: true }} exclude={this.state.toggles} />
<FoodItem title="Beef/Pork Chilli" contents={{ containsMeat: true }} exclude={this.state.toggles} />
<AdvancedFoodItem title="Burgers" extra="Preferably vegan soy or pea protein based burger; ones with beetroot in are nice; not wheat protein based" />
</FoodItemsContainer>
<FoodItemsContainer title="Ingredients / Condiments">
<FoodItem title="Hendo's Relish" />
<FoodItem title="Worcestershire Sauce" contents={{ containsFish: true }} exclude={this.state.toggles} />
<AdvancedFoodItem title="Spicy Mayo for Fries" extra={"Good with fries"} contents={{ containsEggs: true }} exclude={this.state.toggles} />
<AdvancedFoodItem title="Tomato Ketchup" extra={"Can't be too acidic"} exclude={this.state.toggles} />
</FoodItemsContainer>
<br />
<FoodItemsContainer title="Sensory Bads (Do Not Like)">
<AdvancedFoodItem title="Anything Bitter" extra="We are very sensitive to bitter things; way more than most ppl we know; even toast can sometimes be too bitter;" />
<AdvancedFoodItem title="Lettuce" extra="Horrible crunch; only sometimes like the flat leafy kind but only nibbling on the lighter green parts" />
<AdvancedFoodItem title="Spinach Stalks" extra={"Is fine if flattened & Stalks are removed; Is also fine pureed as can't texture then"} />
<AdvancedFoodItem title="Onion" extra={"Too Crunchy; somewhat ok if cooked to remove all texture, fine as a powder or puree but not too sharp tasting"} />
<AdvancedFoodItem title="Firm Mushrooms" extra={"Too Chewy; prefer mushrooms to be boiled or cooked in a way that makes them very soft and not tender"} />
<AdvancedFoodItem title="Button Mushroom Stalks" extra={"Weird Texture"} />
<AdvancedFoodItem title="Fried Shitake Mushroom" extra={"Again, also way too chewy and Bad"} />
<AdvancedFoodItem title="Firm Cooked Carrots" extra={"is Okay but prefer carrots to be cooked until soft enough to be smushed when pressed on"} />
<AdvancedFoodItem title="Firm Cooked Broccoli" extra={"same as carrots"} />
<AdvancedFoodItem title="Firm Cooked Cauliflower" extra={"same as carrots"} />
<AdvancedFoodItem title="Pickles that are too soft" extra={"is ok diced up as a ingredient; but do not like whole, closer to texture of firm cucumber is preferred"} />
<AdvancedFoodItem title="Lettuce" extra="Horrible crunch; only sometimes like the flat leafy kind but only nibbling on the lighter green parts" />
<AdvancedFoodItem title="Some Peppers" extra="Taste of bell peppers and jalapenos Very Bad And Repulsing Cannot Handle" />
<AdvancedFoodItem title={"Peppers & Chillis"} extra="Bad when in large chunks, good when cut up to roughly size of cooked rice when surrounded by other foods of simular or larger size" />
<AdvancedFoodItem title="Raw Garlic" extra={"Too sharp & digestive system isn't a fan; please lightly fry or soften; black garlic is yum"} />
<AdvancedFoodItem title="Beansprouts" extra={"Too Crunch; VERY bad"} />
<AdvancedFoodItem title="Baby Corn Cobs" extra={"Weird texture, never soft enough"} />
<AdvancedFoodItem title="Vegan Cheese" extra={"Can't handle slimy/mucusy texture of most; the ones that puff up into a solid crunchy-ish bubble on pizza are Okay but not the ones that stay soft"} />
<AdvancedFoodItem title="Seitan/Gluten-Based Protein" extra={"Can't handle texture of it, very weird"} />
<AdvancedFoodItem title="Peanut Butter" extra={"Too creamy or crunchy, never a fan of taste"} />
<FoodItem title="Anything else unexpectedly crunchy" />
<FoodItem title="Sparkling Water" />
<FoodItem title="Apple Cider Vinegar" />
<FoodItem title="Anything over our limit of acidity for regular food/sauces" />
<FoodItem title="Aniseed Flavor" />
<AdvancedFoodItem title="Aniseed Liquorice Flavors" extra={"Absolutely love natural liquorice root flavor; hate anise"} />
</FoodItemsContainer>
</>;
}
}

71
src/theme.scss Normal file
View file

@ -0,0 +1,71 @@
@import "../node_modules/@fontsource/comic-neue/latin.css";
@import "../node_modules/@fontsource/opendyslexic/latin.css";
// Configuration
@import "../node_modules/bootstrap/scss/functions";
@import "../node_modules/bootstrap/scss/variables";
@import "../node_modules/bootstrap/scss/mixins";
@import "../node_modules/bootstrap/scss/utilities";
$default-fonts: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
$fonts-comic-sans-neue: "Comic Sans MS", "Comic Neue", $default-fonts;
$fonts-comic-neue: "Comic Neue", $default-fonts;
$fonts-opendyslexic: "OpenDyslexic", $default-fonts;
$font-sans-serif: $fonts-comic-sans-neue;
// Layout & components
@import "../node_modules/bootstrap/scss/root";
@import "../node_modules/bootstrap/scss/reboot";
@import "../node_modules/bootstrap/scss/type";
//@import "../node_modules/bootstrap/scss/images";
@import "../node_modules/bootstrap/scss/containers";
@import "../node_modules/bootstrap/scss/grid";
@import "../node_modules/bootstrap/scss/list-group";
@import "../node_modules/bootstrap/scss/tables";
@import "../node_modules/bootstrap/scss/forms";
@import "../node_modules/bootstrap/scss/buttons";
@import "../node_modules/bootstrap/scss/button-group";
@import "../node_modules/bootstrap/scss/card";
// Helpers
@import "../node_modules/bootstrap/scss/helpers";
// Utilities
@import "../node_modules/bootstrap/scss/utilities/api";
// scss-docs-end import-stack
html {
position: relative;
min-height: 100%;
}
body {
margin-bottom: 60px;
/* Margin bottom by footer height */
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
height: 60px;
/* Set the fixed height of the footer here */
line-height: 60px;
/* Vertically center the text there */
background-color: #f5f5f5;
}
/* for custom theme settings, options in mainPage.tsx as of writing */
html [data-font="default"] {
font-family: $fonts-comic-sans-neue;
}
html [data-font="comicneue"] {
font-family: $fonts-comic-neue;
}
html [data-font="opendyslexic"] {
font-family: $fonts-opendyslexic;
}

40
src/toggleableBox.tsx Normal file
View file

@ -0,0 +1,40 @@
import { Component, createRef } from "preact";
export class ToggleableBox extends Component<{
title: string,
id: string,
checked?: boolean;
onChange?: (checked: boolean) => void,
}> {
inputRef = createRef<HTMLInputElement>();
onChangeInternal(newState: boolean) {
console.debug(`Changed state of ${this.props.id} to ${newState}`);
if (this.props.onChange) {
this.props.onChange(newState);
}
}
public forceChange(status: boolean) {
if (this.inputRef.current) {
let inputElement = this.inputRef.current;
inputElement.checked = status;
}
}
render() {
return <>
<div class="form-check form-switch">
<input
class="form-check-input" type="checkbox" role="switch"
id={this.props.id}
ref={this.inputRef}
onChange={() => {
this.onChangeInternal(this.inputRef.current.checked);
}}
/>
<label class="form-check-label" for={this.props.id}>{this.props.title}</label>
</div>
</>;
}
}

7
src/types.tsx Normal file
View file

@ -0,0 +1,7 @@
export type FoodExcludeTypes = {
containsMeat: boolean;
containsFish: boolean;
containsEggs: boolean;
containsMilk: boolean;
containsAlcohol: boolean;
}

17
tsconfig.json Normal file
View file

@ -0,0 +1,17 @@
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": false,
"allowSyntheticDefaultImports": true,
"module": "es6",
"target": "es2019",
"strictBindCallApply": true,
"strictNullChecks": false,
"noImplicitThis": true,
"allowJs": true,
"strict": true,
"moduleResolution": "node",
"jsx": "react-jsx",
"jsxImportSource": "preact",
}
}

77
webpack-dev.config.js Normal file
View file

@ -0,0 +1,77 @@
const path = require('path');
const TerserPlugin = require("terser-webpack-plugin");
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: "production",
cache: false,
entry: './src/main.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/',
},
stats: {
colors: true,
timings: true,
},
performance: {
hints: false,
},
devtool: "eval-source-map",
plugins: [
new HtmlWebpackPlugin({ title: "Chaos's Food Likes/Dislikes" })
],
devServer: {
historyApiFallback: true,
},
resolve: {
modules: ['node_modules'],
extensions: ['.tsx', '.ts', '.js', ".mjs"],
alias: { os: false }
},
module: {
rules: [
{
test: /\.(scss)$/,
use: [{
loader: 'style-loader',
}, {
loader: 'css-loader',
}, {
loader: 'postcss-loader',
options: {
postcssOptions: {
options: function () {
return [
require('precss'),
require('autoprefixer')
];
}
}
}
}, {
loader: 'sass-loader'
}]
},
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader'
}
]
},
],
},
optimization: {
minimize: false,
minimizer: [
],
},
};

83
webpack.config.js Normal file
View file

@ -0,0 +1,83 @@
const path = require('path');
const TerserPlugin = require("terser-webpack-plugin");
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: "production",
cache: false,
entry: './src/main.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/',
},
stats: {
colors: true,
timings: true,
},
performance: {
hints: false,
},
plugins: [
new HtmlWebpackPlugin({ title: "Chaos's Food Likes/Dislikes" })
],
devServer: {
historyApiFallback: true,
},
resolve: {
modules: ['node_modules'],
extensions: ['.tsx', '.ts', '.js', ".mjs"],
alias: { os: false }
},
module: {
rules: [
{
test: /\.(scss)$/,
use: [{
loader: 'style-loader',
}, {
loader: 'css-loader',
}, {
loader: 'postcss-loader',
options: {
postcssOptions: {
options: function () {
return [
require('precss'),
require('autoprefixer')
];
}
}
}
}, {
loader: 'sass-loader'
}]
},
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader'
}
]
},
],
},
optimization: {
minimize: true,
minimizer: [
`...`,
new TerserPlugin({
terserOptions: {
ecma: "2015"
}
}),
new CssMinimizerPlugin(),
],
},
};