mirror of
https://github.com/tlsnotary/explorer.git
synced 2026-01-08 04:23:52 -05:00
chore: add boilerplate for react + redux
This commit is contained in:
3
.babelrc
Normal file
3
.babelrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"]
|
||||
}
|
||||
36
.eslintrc
Normal file
36
.eslintrc
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": ["prettier", "plugin:@typescript-eslint/recommended"],
|
||||
"plugins": ["prettier", "@typescript-eslint"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"@typescript-eslint/no-explicit-any": 1,
|
||||
"@typescript-eslint/no-var-requires": 0,
|
||||
"@typescript-eslint/ban-ts-comment": 0,
|
||||
"no-undef": "error",
|
||||
"padding-line-between-statements": "error"
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": "latest"
|
||||
},
|
||||
"env": {
|
||||
"webextensions": true,
|
||||
"es6": true,
|
||||
"browser": true,
|
||||
"node": true
|
||||
},
|
||||
"settings": {
|
||||
"import/resolver": "typescript"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"node_modules",
|
||||
"zip",
|
||||
"build",
|
||||
"wasm",
|
||||
"tlsn",
|
||||
"util",
|
||||
"webpack.config.js"
|
||||
]
|
||||
}
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -0,0 +1,4 @@
|
||||
**/node_modules
|
||||
**/.DS_Store
|
||||
.idea
|
||||
build
|
||||
|
||||
8
.prettierignore
Normal file
8
.prettierignore
Normal file
@@ -0,0 +1,8 @@
|
||||
build
|
||||
node_modules
|
||||
wasm
|
||||
tlsn
|
||||
postcss.config.js
|
||||
webpack.config.js
|
||||
*.json
|
||||
*.scss
|
||||
9
.prettierrc.json
Normal file
9
.prettierrc.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"bracketSpacing": true,
|
||||
"jsxBracketSameLine": false,
|
||||
"arrowParens": "always"
|
||||
}
|
||||
13555
package-lock.json
generated
Normal file
13555
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
69
package.json
69
package.json
@@ -4,7 +4,8 @@
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"build": "NODE_ENV=production webpack --config webpack.config.js",
|
||||
"dev": "NODE_ENV=development webpack-dev-server --config webpack.config.js --hot"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -15,5 +16,71 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/tlsnotary/explorer/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.4.2",
|
||||
"buffer": "^6.0.3",
|
||||
"charwise": "^3.0.1",
|
||||
"classnames": "^2.3.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-redux": "^8.1.2",
|
||||
"react-router": "^6.15.0",
|
||||
"react-router-dom": "^6.15.0",
|
||||
"redux": "^4.2.1",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-thunk": "^2.4.2",
|
||||
"tailwindcss": "^3.3.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.12",
|
||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
|
||||
"@types/chrome": "^0.0.202",
|
||||
"@types/node": "^20.4.10",
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.10",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"@types/redux-logger": "^3.0.9",
|
||||
"@types/webextension-polyfill": "^0.10.7",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
"babel-preset-react-app": "^10.0.1",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"css-loader": "^6.7.3",
|
||||
"eslint": "^8.31.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"eslint-plugin-flowtype": "^8.0.3",
|
||||
"eslint-plugin-import": "^2.27.4",
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"eslint-plugin-react": "^7.32.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^11.1.0",
|
||||
"html-loader": "^4.2.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"postcss-loader": "^7.3.3",
|
||||
"postcss-preset-env": "^9.1.1",
|
||||
"prettier": "^3.0.2",
|
||||
"react-refresh": "^0.14.0",
|
||||
"react-refresh-typescript": "^2.0.7",
|
||||
"sass": "^1.57.1",
|
||||
"sass-loader": "^13.2.0",
|
||||
"source-map-loader": "^3.0.1",
|
||||
"style-loader": "^3.3.1",
|
||||
"terser-webpack-plugin": "^5.3.6",
|
||||
"ts-loader": "^9.4.2",
|
||||
"type-fest": "^3.5.2",
|
||||
"typescript": "^4.9.4",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
},
|
||||
"homepage": "https://github.com/tlsnotary/explorer#readme"
|
||||
}
|
||||
|
||||
4
postcss.config.js
Normal file
4
postcss.config.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const tailwindcss = require("tailwindcss");
|
||||
module.exports = {
|
||||
plugins: ["postcss-preset-env", tailwindcss],
|
||||
};
|
||||
45
src/components/Button/index.scss
Normal file
45
src/components/Button/index.scss
Normal file
@@ -0,0 +1,45 @@
|
||||
.button {
|
||||
@apply bg-slate-100;
|
||||
@apply text-slate-500;
|
||||
@apply font-bold;
|
||||
@apply px-2 py-0.5;
|
||||
user-select: none;
|
||||
|
||||
&:hover {
|
||||
@apply text-slate-600;
|
||||
@apply bg-slate-200;
|
||||
}
|
||||
|
||||
&:active {
|
||||
@apply text-slate-700;
|
||||
@apply bg-slate-300;
|
||||
}
|
||||
|
||||
&--primary {
|
||||
@apply bg-primary/[0.8];
|
||||
@apply text-white;
|
||||
|
||||
&:hover {
|
||||
@apply bg-primary/[0.9];
|
||||
@apply text-white;
|
||||
}
|
||||
|
||||
&:active {
|
||||
@apply bg-primary;
|
||||
@apply text-white;
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
@apply opacity-50;
|
||||
@apply select-none;
|
||||
|
||||
&:hover {
|
||||
@apply text-slate-400;
|
||||
}
|
||||
|
||||
&:active {
|
||||
@apply text-slate-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/components/Button/index.tsx
Normal file
41
src/components/Button/index.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import React, { ButtonHTMLAttributes, ReactElement } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './index.scss';
|
||||
import Icon from '../Icon';
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
btnType?: 'primary' | 'secondary' | '';
|
||||
loading?: boolean;
|
||||
} & ButtonHTMLAttributes<HTMLButtonElement>;
|
||||
|
||||
export default function Button(props: Props): ReactElement {
|
||||
const {
|
||||
className,
|
||||
btnType = '',
|
||||
children,
|
||||
onClick,
|
||||
disabled,
|
||||
loading,
|
||||
// Must select all non-button props here otherwise react-dom will show warning
|
||||
...btnProps
|
||||
} = props;
|
||||
return (
|
||||
<button
|
||||
className={classNames(
|
||||
'flex flex-row flex-nowrap items-center',
|
||||
'h-10 px-4 button transition-colors',
|
||||
{
|
||||
'button--primary': btnType === 'primary',
|
||||
'button--secondary': btnType === 'secondary',
|
||||
'cursor-default': disabled || loading,
|
||||
},
|
||||
className
|
||||
)}
|
||||
onClick={!disabled && !loading ? onClick : undefined}
|
||||
disabled={disabled || loading}
|
||||
{...btnProps}>
|
||||
{loading ? <Icon className="animate-spin" fa="fa-solid fa-spinner" size={2} /> : children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
0
src/components/Icon/index.scss
Normal file
0
src/components/Icon/index.scss
Normal file
37
src/components/Icon/index.tsx
Normal file
37
src/components/Icon/index.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import React, { MouseEventHandler, ReactElement, ReactNode } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import './index.scss';
|
||||
|
||||
type Props = {
|
||||
url?: string;
|
||||
fa?: string;
|
||||
className?: string;
|
||||
size?: number;
|
||||
onClick?: MouseEventHandler;
|
||||
children?: ReactNode;
|
||||
};
|
||||
|
||||
export default function Icon(props: Props): ReactElement {
|
||||
const { url, size = 1, className = '', fa, onClick, children } = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'bg-contain bg-center bg-no-repeat icon',
|
||||
{
|
||||
'cursor-pointer': onClick,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
style={{
|
||||
backgroundImage: url ? `url(${url})` : undefined,
|
||||
width: !fa ? `${size}rem` : undefined,
|
||||
height: !fa ? `${size}rem` : undefined,
|
||||
}}
|
||||
onClick={onClick}
|
||||
>
|
||||
{!url && !!fa && <i className={fa} style={{ fontSize: `${size}rem` }} />}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
22
src/index.tsx
Normal file
22
src/index.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'isomorphic-fetch';
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import store from './store';
|
||||
import App from './pages/App';
|
||||
|
||||
(async () => {
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</Provider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
})();
|
||||
|
||||
if ((module as any).hot) {
|
||||
(module as any).hot.accept();
|
||||
}
|
||||
10
src/pages/App/index.scss
Normal file
10
src/pages/App/index.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
$fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
|
||||
|
||||
@import "../../../node_modules/@fortawesome/fontawesome-free/scss/fontawesome";
|
||||
@import "../../../node_modules/@fortawesome/fontawesome-free/scss/brands";
|
||||
@import "../../../node_modules/@fortawesome/fontawesome-free/scss/solid";
|
||||
@import "../../../node_modules/@fortawesome/fontawesome-free/scss/regular";
|
||||
23
src/pages/App/index.tsx
Normal file
23
src/pages/App/index.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import React, { ReactElement } from 'react';
|
||||
import "./index.scss";
|
||||
import Button from '../../components/Button';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { asyncIncrementCounter, incrementCounter, useCounter, useLoading } from '../../store/counter';
|
||||
|
||||
export default function App(): ReactElement {
|
||||
const dispatch = useDispatch();
|
||||
const counter = useCounter();
|
||||
const loading = useLoading();
|
||||
|
||||
return (
|
||||
<div className="app flex flex-col gap-4">
|
||||
{`Clicked ${counter} times`}
|
||||
<Button className="w-fit" onClick={() => dispatch(incrementCounter())}>
|
||||
Increment
|
||||
</Button>
|
||||
<Button className="w-fit" onClick={() => dispatch(asyncIncrementCounter(1000))} loading={loading}>
|
||||
Wait 1s + Increment
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
80
src/store/counter.ts
Normal file
80
src/store/counter.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
import deepEqual from 'fast-deep-equal';
|
||||
import type { AppRootState } from './index';
|
||||
import { Dispatch } from 'redux';
|
||||
|
||||
export enum ActionType {
|
||||
Increment = 'counter/increment',
|
||||
SetLoading = 'counter/setLoading',
|
||||
}
|
||||
|
||||
export type Action<payload = any> = {
|
||||
type: ActionType;
|
||||
payload: payload;
|
||||
error?: boolean;
|
||||
meta?: any;
|
||||
};
|
||||
|
||||
type State = {
|
||||
value: number;
|
||||
loading: boolean;
|
||||
};
|
||||
|
||||
const initState: State = {
|
||||
value: 0,
|
||||
loading: false,
|
||||
};
|
||||
|
||||
export const incrementCounter = (): Action => ({
|
||||
type: ActionType.Increment,
|
||||
payload: null,
|
||||
});
|
||||
|
||||
export const setLoading = (loading = false): Action<boolean> => ({
|
||||
type: ActionType.SetLoading,
|
||||
payload: loading,
|
||||
});
|
||||
|
||||
export const asyncIncrementCounter = (timeout = 1000): any => async (dispatch: Dispatch, getState: () => AppRootState) => {
|
||||
dispatch(setLoading(true));
|
||||
await new Promise(r => setTimeout(r, timeout));
|
||||
dispatch(incrementCounter());
|
||||
dispatch(setLoading(false));
|
||||
};
|
||||
|
||||
export default function counter(state = initState, action: Action): State {
|
||||
switch (action.type) {
|
||||
case ActionType.Increment:
|
||||
return handleIncrement(state, action);
|
||||
case ActionType.SetLoading:
|
||||
return handleSetLoading(state, action);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
function handleIncrement(state: State, action: Action): State {
|
||||
return {
|
||||
...state,
|
||||
value: state.value + 1,
|
||||
};
|
||||
}
|
||||
|
||||
function handleSetLoading(state: State, action: Action<boolean>): State {
|
||||
return {
|
||||
...state,
|
||||
loading: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
export function useCounter() {
|
||||
return useSelector((state: AppRootState) => {
|
||||
return state.counter.value;
|
||||
}, deepEqual);
|
||||
}
|
||||
|
||||
export function useLoading() {
|
||||
return useSelector((state: AppRootState) => {
|
||||
return state.counter.loading;
|
||||
}, deepEqual);
|
||||
}
|
||||
32
src/store/index.ts
Normal file
32
src/store/index.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { applyMiddleware, combineReducers, createStore } from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
import { createLogger } from 'redux-logger';
|
||||
import counter from './counter';
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
counter,
|
||||
});
|
||||
|
||||
export type AppRootState = ReturnType<typeof rootReducer>;
|
||||
|
||||
const createStoreWithMiddleware =
|
||||
process.env.NODE_ENV === 'development'
|
||||
? applyMiddleware(
|
||||
thunk,
|
||||
createLogger({
|
||||
collapsed: true,
|
||||
}),
|
||||
)(createStore)
|
||||
: applyMiddleware(
|
||||
thunk,
|
||||
)(createStore);
|
||||
|
||||
function configureAppStore() {
|
||||
return createStoreWithMiddleware(
|
||||
rootReducer,
|
||||
);
|
||||
}
|
||||
|
||||
const store = configureAppStore();
|
||||
|
||||
export default store;
|
||||
12
static/index.html
Normal file
12
static/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Popup</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<div id="modal-root"></div>
|
||||
</body>
|
||||
</html>
|
||||
12
tailwind.config.js
Normal file
12
tailwind.config.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ['./src/**/*.{js,jsx,ts,tsx}'],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: '#243f5f',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
20
tsconfig.json
Normal file
20
tsconfig.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": false,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"noEmit": false,
|
||||
"jsx": "react"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["build", "node_modules"]
|
||||
}
|
||||
169
webpack.config.js
Executable file
169
webpack.config.js
Executable file
@@ -0,0 +1,169 @@
|
||||
var webpack = require("webpack"),
|
||||
path = require("path"),
|
||||
CopyWebpackPlugin = require("copy-webpack-plugin"),
|
||||
HtmlWebpackPlugin = require("html-webpack-plugin"),
|
||||
TerserPlugin = require("terser-webpack-plugin");
|
||||
var { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
var ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
|
||||
var ReactRefreshTypeScript = require("react-refresh-typescript");
|
||||
|
||||
const ASSET_PATH = process.env.ASSET_PATH || "/";
|
||||
|
||||
var alias = {};
|
||||
|
||||
var fileExtensions = [
|
||||
"jpg",
|
||||
"jpeg",
|
||||
"png",
|
||||
"gif",
|
||||
"eot",
|
||||
"otf",
|
||||
"svg",
|
||||
"ttf",
|
||||
"woff",
|
||||
"woff2",
|
||||
];
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== "production";
|
||||
|
||||
var options = {
|
||||
mode: process.env.NODE_ENV || "development",
|
||||
ignoreWarnings: [
|
||||
/Circular dependency between chunks with runtime/,
|
||||
/ResizeObserver loop completed with undelivered notifications/
|
||||
],
|
||||
entry: {
|
||||
index: path.join(__dirname, "src", "index.tsx"),
|
||||
},
|
||||
output: {
|
||||
filename: "[name].bundle.js",
|
||||
path: path.resolve(__dirname, "build"),
|
||||
clean: true,
|
||||
publicPath: ASSET_PATH,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
// look for .css or .scss files
|
||||
test: /\.(css|scss)$/,
|
||||
// in the `src` directory
|
||||
use: [
|
||||
{
|
||||
loader: "style-loader",
|
||||
},
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: { importLoaders: 1 },
|
||||
},
|
||||
{
|
||||
loader: "postcss-loader",
|
||||
},
|
||||
{
|
||||
loader: "sass-loader",
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: new RegExp(".(" + fileExtensions.join("|") + ")$"),
|
||||
type: "asset/resource",
|
||||
exclude: /node_modules/,
|
||||
// loader: 'file-loader',
|
||||
// options: {
|
||||
// name: '[name].[ext]',
|
||||
// },
|
||||
},
|
||||
{
|
||||
test: /\.html$/,
|
||||
loader: "html-loader",
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.(ts|tsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: require.resolve("ts-loader"),
|
||||
options: {
|
||||
getCustomTransformers: () => ({
|
||||
before: [isDevelopment && ReactRefreshTypeScript()].filter(
|
||||
Boolean
|
||||
),
|
||||
}),
|
||||
transpileOnly: isDevelopment,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
use: [
|
||||
{
|
||||
loader: "source-map-loader",
|
||||
},
|
||||
{
|
||||
loader: require.resolve("babel-loader"),
|
||||
options: {
|
||||
plugins: [
|
||||
isDevelopment && require.resolve("react-refresh/babel"),
|
||||
].filter(Boolean),
|
||||
},
|
||||
},
|
||||
],
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
alias: alias,
|
||||
extensions: fileExtensions
|
||||
.map((extension) => "." + extension)
|
||||
.concat([".js", ".jsx", ".ts", ".tsx", ".css"]),
|
||||
},
|
||||
plugins: [
|
||||
isDevelopment && new ReactRefreshWebpackPlugin(),
|
||||
new CleanWebpackPlugin({ verbose: false }),
|
||||
new webpack.ProgressPlugin(),
|
||||
// expose and write the allowed env vars on the compiled bundle
|
||||
new webpack.EnvironmentPlugin(["NODE_ENV"]),
|
||||
new HtmlWebpackPlugin({
|
||||
template: path.join(__dirname, "static", "index.html"),
|
||||
filename: "index.html",
|
||||
chunks: ["index"],
|
||||
cache: false,
|
||||
}),
|
||||
new webpack.ProvidePlugin({
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
}),
|
||||
].filter(Boolean),
|
||||
infrastructureLogging: {
|
||||
level: "info",
|
||||
},
|
||||
// Required by wasm-bindgen-rayon, in order to use SharedArrayBuffer on the Web
|
||||
// Ref:
|
||||
// - https://github.com/GoogleChromeLabs/wasm-bindgen-rayon#setting-up
|
||||
// - https://web.dev/i18n/en/coop-coep/
|
||||
devServer: {
|
||||
headers: {
|
||||
'Cross-Origin-Embedder-Policy': 'require-corp',
|
||||
'Cross-Origin-Opener-Policy': 'same-origin',
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
options.devtool = "cheap-module-source-map";
|
||||
} else {
|
||||
options.optimization = {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
extractComments: false,
|
||||
}),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = options;
|
||||
Reference in New Issue
Block a user