Update to be compatible with new SecureFile version
This commit is contained in:
parent
944e3d2f11
commit
bca3049c27
6272
package-lock.json
generated
6272
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
43
package.json
43
package.json
@ -13,26 +13,33 @@
|
||||
"last 2 Chrome versions"
|
||||
],
|
||||
"dependencies": {
|
||||
"@hibas123/secure-file-wrapper": "^2.5.1",
|
||||
"@hibas123/theme": "^1.0.5",
|
||||
"@hibas123/utils": "^2.2.17",
|
||||
"@codemirror/commands": "^6.6.0",
|
||||
"@codemirror/lang-markdown": "^6.2.5",
|
||||
"@hibas123/secure-file-wrapper": "^2.5.3",
|
||||
"@hibas123/theme": "^2.0.7",
|
||||
"@hibas123/utils": "^2.2.18",
|
||||
"aes-js": "^3.1.2",
|
||||
"codemirror": "^5.58.3",
|
||||
"feather-icons": "^4.28.0",
|
||||
"idb": "^5.0.7",
|
||||
"js-sha256": "^0.9.0",
|
||||
"codemirror": "^6.0.1",
|
||||
"easymde": "^2.18.0",
|
||||
"feather-icons": "^4.29.2",
|
||||
"idb": "^5.0.8",
|
||||
"js-sha256": "^0.11.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"parcel": "^1.12.4",
|
||||
"preact": "^10.5.7",
|
||||
"preact-feather": "^4.1.0",
|
||||
"secure-file-wrapper": "git+https://git.stamm.me/OpenServer/OSSecureFileWrapper.git",
|
||||
"uuid": "^8.3.1"
|
||||
"parcel": "^2.12.0",
|
||||
"preact": "^10.22.0",
|
||||
"preact-feather": "^4.2.1",
|
||||
"uuid": "^10.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/codemirror": "0.0.99",
|
||||
"@types/lodash.clonedeep": "^4.5.6",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"sass": "^1.29.0",
|
||||
"typescript": "^4.1.2"
|
||||
"@parcel/packager-raw-url": "2.12.0",
|
||||
"@parcel/transformer-sass": "^2.12.0",
|
||||
"@parcel/transformer-webmanifest": "^2.12.0",
|
||||
"@types/codemirror": "5.60.15",
|
||||
"@types/lodash.clonedeep": "^4.5.9",
|
||||
"@types/uuid": "^10.0.0",
|
||||
"process": "^0.11.10",
|
||||
"sass": "^1.77.6",
|
||||
"typescript": "^5.5.2"
|
||||
}
|
||||
}
|
||||
}
|
3701
pnpm-lock.yaml
Normal file
3701
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,13 @@
|
||||
import { h } from "preact";
|
||||
import { useEffect, useRef } from "preact/hooks";
|
||||
|
||||
import * as CM from "codemirror";
|
||||
import "codemirror/lib/codemirror.css";
|
||||
import "codemirror/theme/base16-dark.css";
|
||||
import { EditorView, basicSetup, } from "codemirror";
|
||||
import { EditorState, Text } from "@codemirror/state";
|
||||
import { defaultKeymap } from "@codemirror/commands"
|
||||
|
||||
import { markdown } from "@codemirror/lang-markdown"
|
||||
// import "codemirror/lib/codemirror.css";
|
||||
// import "codemirror/theme/base16-dark.css";
|
||||
|
||||
import "./CodeMirror.scss";
|
||||
import Theme from "../theme";
|
||||
@ -18,27 +22,41 @@ interface ICodeMirrorProps {
|
||||
export default function CodeMirror(props: ICodeMirrorProps) {
|
||||
const ref = useRef<HTMLTextAreaElement>();
|
||||
useEffect(() => {
|
||||
const instance = CM.fromTextArea(ref.current, {
|
||||
value: props.value,
|
||||
mode: "markdown",
|
||||
lineNumbers: true,
|
||||
lineWrapping: true,
|
||||
theme: Theme.isDark.value ? "base16-dark" : "default",
|
||||
viewportMargin: Infinity,
|
||||
// extraKeys: {
|
||||
// "Ctrl-S": (cm) => {
|
||||
// const val = cm.getValue();
|
||||
// props?.onSave(val);
|
||||
// },
|
||||
// Esc: props.onClose,
|
||||
// },
|
||||
const instance = new EditorView({
|
||||
parent: ref.current,
|
||||
extensions: [
|
||||
basicSetup,
|
||||
markdown(),
|
||||
|
||||
],
|
||||
})
|
||||
// const instance = CM.(ref.current, {
|
||||
// value: props.value,
|
||||
// mode: "markdown",
|
||||
// lineNumbers: true,
|
||||
// lineWrapping: true,
|
||||
// theme: Theme.isDark.value ? "base16-dark" : "default",
|
||||
// viewportMargin: Infinity,
|
||||
// // extraKeys: {
|
||||
// // "Ctrl-S": (cm) => {
|
||||
// // const val = cm.getValue();
|
||||
// // props?.onSave(val);
|
||||
// // },
|
||||
// // Esc: props.onClose,
|
||||
// // },
|
||||
// });
|
||||
|
||||
const state = EditorState.create({
|
||||
doc: Text.of([props.value ?? ""]),
|
||||
});
|
||||
|
||||
if (props.value) instance.setValue(props.value);
|
||||
instance.setState(state);
|
||||
instance.focus();
|
||||
state.
|
||||
|
||||
instance.on("change", () => props?.onChange(instance.getValue()));
|
||||
instance.on("change", () => props?.onChange(instance.getValue()));
|
||||
|
||||
return () => {};
|
||||
return () => { };
|
||||
}, [ref]);
|
||||
return <textarea ref={ref}></textarea>;
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ export class Footer extends Component<
|
||||
<span>
|
||||
Welcome <b>{Notes.name}</b>
|
||||
</span>
|
||||
<span style="color: lightgrey;">v1.6</span>
|
||||
<span style="color: lightgrey;">v1.7</span>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
27
src/components/routes/vault/EasyMde.tsx
Normal file
27
src/components/routes/vault/EasyMde.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { h } from "preact";
|
||||
|
||||
import * as EasyMDE from "easymde";
|
||||
import "easymde/dist/easymde.min.css"
|
||||
// import "./easymde.scss"
|
||||
import { useEffect, useRef } from "preact/hooks";
|
||||
|
||||
export default function EasyMDEPreact(props: { value: string, onChange: (value: string) => void }) {
|
||||
const ref = useRef<HTMLTextAreaElement>();
|
||||
useEffect(() => {
|
||||
const mde = new EasyMDE({
|
||||
element: ref.current,
|
||||
initialValue: props.value
|
||||
})
|
||||
|
||||
mde.codemirror.on("change", () => {
|
||||
props.onChange(mde.value());
|
||||
});
|
||||
|
||||
return () => {
|
||||
mde.cleanup();
|
||||
}
|
||||
}, [ref])
|
||||
return <div style="background: white;">
|
||||
<textarea ref={ref}></textarea>
|
||||
</div>
|
||||
}
|
@ -2,12 +2,16 @@ import { h, Component } from "preact";
|
||||
import { IVault, ViewNote } from "../../../notes";
|
||||
import { Trash2 as Trash, X, Save } from "preact-feather";
|
||||
|
||||
import Navigation from "../../../navigation";
|
||||
// import Navigation from "../../../navigation";
|
||||
import { YesNoModal } from "../../modals/YesNoModal";
|
||||
import Notifications, { MessageType } from "../../../notifications";
|
||||
import CodeMirror from "../../CodeMirror";
|
||||
// import CodeMirror from "../../CodeMirror";
|
||||
|
||||
|
||||
|
||||
import { useEffect, useMemo, useState } from "preact/hooks";
|
||||
import { usePromise } from "../../../hooks";
|
||||
import EasyMDEPreact from "./EasyMde";
|
||||
|
||||
interface IEntryProps {
|
||||
vault: IVault;
|
||||
@ -114,14 +118,14 @@ export default function Entry(props: IEntryProps) {
|
||||
</div>
|
||||
</header>
|
||||
<div class="container" style="padding: 0">
|
||||
<CodeMirror
|
||||
<EasyMDEPreact
|
||||
value={text}
|
||||
onChange={(value) => {
|
||||
setChanged(true);
|
||||
setText(value);
|
||||
}}
|
||||
// onSave={save}
|
||||
// onClose={close}
|
||||
// onSave={save}
|
||||
// onClose={close}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -32,7 +32,7 @@ export default class VaultsPage extends Page<
|
||||
|
||||
updateVaults(s?: boolean) {
|
||||
if (s) return;
|
||||
return new Promise((yes) => {
|
||||
return new Promise<void>((yes) => {
|
||||
Notes.getVaults().then((vaults) => this.setState({ vaults }, yes));
|
||||
});
|
||||
}
|
||||
@ -245,6 +245,7 @@ export default class VaultsPage extends Page<
|
||||
}
|
||||
|
||||
render() {
|
||||
console.log({ vaults: this.state.vaults })
|
||||
let elms = this.state.vaults.map((vault) => {
|
||||
return (
|
||||
<li
|
||||
|
@ -1,70 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>SecureNotes</title>
|
||||
<meta charset="utf8" />
|
||||
<meta name="Description" content="Notes app" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<link rel="manifest" href="./manifest.webmanifest" />
|
||||
<!-- <link rel="shortcut icon" href="/public/icon-72x72.png"> -->
|
||||
|
||||
<!-- Add to home screen for Safari on iOS -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<meta name="apple-mobile-web-app-title" content="Secure Notes" />
|
||||
<head>
|
||||
<title>SecureNotes</title>
|
||||
<meta charset="utf8" />
|
||||
<meta name="Description" content="Notes app" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<link rel="manifest" href="./manifest.webmanifest" />
|
||||
<!-- <link rel="shortcut icon" href="/public/icon-72x72.png"> -->
|
||||
|
||||
<!-- sizes="180x180" -->
|
||||
<!-- href="/public/apple-touch-icon.png" -->
|
||||
<!-- Add to home screen for Safari on iOS -->
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<meta name="apple-mobile-web-app-title" content="Secure Notes" />
|
||||
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="256x256"
|
||||
href="/public/notepad256.png"
|
||||
/>
|
||||
<!-- <link
|
||||
<!-- sizes="180x180" -->
|
||||
<!-- href="/public/apple-touch-icon.png" -->
|
||||
|
||||
<link rel="apple-touch-icon" sizes="256x256" href="./public/notepad256.png" />
|
||||
<!-- <link
|
||||
rel="mask-icon"
|
||||
href="/public/safari-pinned-tab.svg"
|
||||
color="#1E88E5"
|
||||
/> -->
|
||||
<meta name="msapplication-TileColor" content="#1E88E5" />
|
||||
<meta name="theme-color" content="#1E88E5" />
|
||||
</head>
|
||||
<meta name="msapplication-TileColor" content="#1E88E5" />
|
||||
<meta name="theme-color" content="#1E88E5" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript> You have to enable JavaScript to use this site! </noscript>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
if (navigator.serviceWorker.controller) {
|
||||
if (localStorage.getItem("debug")) {
|
||||
console.warn(
|
||||
"Debuggung and service worker found, make shure to clear cache!"
|
||||
);
|
||||
}
|
||||
console.log("active service worker found, no need to register");
|
||||
} else {
|
||||
if (localStorage.getItem("debug")) {
|
||||
console.warn("Disabling Service Worker in debug mode!");
|
||||
} else {
|
||||
// Register the ServiceWorker
|
||||
navigator.serviceWorker
|
||||
.register("serviceworker.js", {
|
||||
scope: "/",
|
||||
})
|
||||
.then(function (reg) {
|
||||
console.log(
|
||||
"Service worker has been registered for scope:" +
|
||||
reg.scope
|
||||
);
|
||||
navigator.serviceWorker.controller.addEventListener(
|
||||
"cleared_cache",
|
||||
(evt) => {
|
||||
console.log(evt);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
<body>
|
||||
<noscript> You have to enable JavaScript to use this site! </noscript>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
window.debug = {}
|
||||
</script>
|
||||
<script src="index.tsx" type="module"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,42 +1,3 @@
|
||||
declare global {
|
||||
interface Window {
|
||||
requestIdleCallback: (
|
||||
callback: (deadline: {
|
||||
didTimeout: boolean;
|
||||
timeRemaining: () => number;
|
||||
}) => void,
|
||||
options?: { timeout: number }
|
||||
) => number | NodeJS.Timeout;
|
||||
cancelIdleCallback: (id: number | NodeJS.Timeout) => void;
|
||||
debug: any;
|
||||
}
|
||||
|
||||
// namespace JSX {
|
||||
// interface IntrinsicElements {
|
||||
// "wired-button": HTMLAttributes;
|
||||
// "wired-card": HTMLAttributes;
|
||||
// "wired-checkbox": HTMLAttributes;
|
||||
// "wired-combo": HTMLAttributes;
|
||||
// "wired-fab": HTMLAttributes;
|
||||
// "wired-icon-button": HTMLAttributes;
|
||||
// "wired-input": HTMLAttributes;
|
||||
// "wired-item": HTMLAttributes;
|
||||
// "wired-lib": HTMLAttributes;
|
||||
// "wired-listbox": HTMLAttributes;
|
||||
// "wired-progress": HTMLAttributes;
|
||||
// "wired-radio-group": HTMLAttributes;
|
||||
// "wired-radio": HTMLAttributes;
|
||||
// "wired-slider": HTMLAttributes;
|
||||
// "wired-spinner": HTMLAttributes;
|
||||
// "wired-tabs": HTMLAttributes;
|
||||
// "wired-textarea": HTMLAttributes;
|
||||
// "wired-toggle": HTMLAttributes;
|
||||
// "wired-tooltip": HTMLAttributes;
|
||||
|
||||
// }
|
||||
// }
|
||||
}
|
||||
declare const window: Window;
|
||||
|
||||
window.requestIdleCallback =
|
||||
window.requestIdleCallback ||
|
||||
@ -119,7 +80,7 @@ console.log("Dark mode:", Theme.active);
|
||||
}
|
||||
|
||||
Navigation.default = VaultsPage as typeof Page;
|
||||
Navigation.addPage("/vault", VaultPage as typeof Page);
|
||||
Navigation.addPage("/vault", VaultPage as any as typeof Page);
|
||||
Navigation.addPage("/demo", DemoPage as typeof Page);
|
||||
Navigation.addPage("/share", SharePage as typeof Page);
|
||||
Navigation.addPage("/settings", SettingsPage as typeof Page);
|
||||
@ -137,3 +98,35 @@ console.log("Dark mode:", Theme.active);
|
||||
|
||||
render(<App />, document.body, document.getElementById("app"));
|
||||
})();
|
||||
|
||||
|
||||
if (navigator.serviceWorker.controller) {
|
||||
if (localStorage.getItem("debug")) {
|
||||
console.warn(
|
||||
"Debuggung and service worker found, make shure to clear cache!"
|
||||
);
|
||||
}
|
||||
console.log("active service worker found, no need to register");
|
||||
} else {
|
||||
if (localStorage.getItem("debug")) {
|
||||
console.warn("Disabling Service Worker in debug mode!");
|
||||
} else {
|
||||
// Register the ServiceWorker
|
||||
navigator.serviceWorker
|
||||
.register(new URL("serviceworker.js", import.meta.url), {
|
||||
scope: "/",
|
||||
})
|
||||
.then(function (reg) {
|
||||
console.log(
|
||||
"Service worker has been registered for scope:" +
|
||||
reg.scope
|
||||
);
|
||||
navigator.serviceWorker.controller.addEventListener(
|
||||
"cleared_cache",
|
||||
(evt) => {
|
||||
console.log(evt);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
24
src/notes.ts
24
src/notes.ts
@ -8,6 +8,7 @@ import * as config from "../config.json";
|
||||
import * as b64 from "./helper/base64";
|
||||
import IDB from "./helper/indexeddb";
|
||||
import Notifications, { MessageType } from "./notifications";
|
||||
import { cloneDeep } from "lodash";
|
||||
|
||||
export class HttpError extends Error {
|
||||
constructor(public status: number, public statusText: string) {
|
||||
@ -37,8 +38,6 @@ export interface ViewNote extends BaseNote {
|
||||
__value: string;
|
||||
}
|
||||
|
||||
import clonedeep = require("lodash.clonedeep");
|
||||
|
||||
const Encoder = new TextEncoder();
|
||||
const Decoder = new TextDecoder();
|
||||
|
||||
@ -129,11 +128,10 @@ class NotesProvider {
|
||||
}
|
||||
|
||||
login() {
|
||||
window.location.href = `${config.auth_server}/auth?client_id=${
|
||||
config.client_id
|
||||
}&scope=${config.permission}&redirect_uri=${encodeURIComponent(
|
||||
config.callback_url
|
||||
)}&response_type=code`;
|
||||
window.location.href = `${config.auth_server}/auth?client_id=${config.client_id
|
||||
}&scope=${config.permission}&redirect_uri=${encodeURIComponent(
|
||||
config.callback_url
|
||||
)}&response_type=code`;
|
||||
}
|
||||
|
||||
async getToken(code: string) {
|
||||
@ -193,8 +191,8 @@ class NotesProvider {
|
||||
console.log("Getting JWT");
|
||||
let req = await fetch(
|
||||
config.auth_server +
|
||||
"/api/oauth/jwt?refreshtoken=" +
|
||||
localStorage.getItem("refreshtoken")
|
||||
"/api/oauth/jwt?refreshtoken=" +
|
||||
localStorage.getItem("refreshtoken")
|
||||
);
|
||||
if (req.status !== 200) {
|
||||
Notifications.sendNotification("offline", MessageType.INFO);
|
||||
@ -356,7 +354,7 @@ class NotesProvider {
|
||||
let value = await this._secureFile.get(id);
|
||||
let note: DBNote = {
|
||||
_id: remote._id,
|
||||
folder: remote.folder,
|
||||
folder: remote.active.folder,
|
||||
preview: b64.decode(remote.active.preview || ""),
|
||||
time: remote.active.time,
|
||||
__value: new Uint8Array(value),
|
||||
@ -578,7 +576,7 @@ class NotesProvider {
|
||||
.filter((e) => e.folder === this.vault._id)
|
||||
.sort(this.sort)
|
||||
.map<BaseNote>((e) => {
|
||||
let new_note = clonedeep(<Note>e) as BaseNote;
|
||||
let new_note = cloneDeep(<Note>e) as BaseNote;
|
||||
delete (<any>new_note).__value;
|
||||
new_note.preview = this.decrypt(e.preview);
|
||||
return new_note;
|
||||
@ -610,7 +608,7 @@ class NotesProvider {
|
||||
const tx = Notes.database.transaction(Notes.noteDB, Notes.oplogDB);
|
||||
let old_note = await Notes.noteDB.get(note._id, tx);
|
||||
|
||||
let new_note = clonedeep(<Note>note) as DBNote;
|
||||
let new_note = cloneDeep(<Note>note) as DBNote;
|
||||
new_note.__value = this.encrypt(note.__value);
|
||||
let [title, preview] = note.__value.split("\n");
|
||||
if (preview) preview = "\n" + preview;
|
||||
@ -637,7 +635,7 @@ class NotesProvider {
|
||||
async getNote(id: string): Promise<ViewNote> {
|
||||
let note = await Notes.noteDB.get(id);
|
||||
if (!note) return undefined;
|
||||
let new_note = clonedeep(<Note>note) as ViewNote;
|
||||
let new_note = cloneDeep(<Note>note) as ViewNote;
|
||||
new_note.__value = this.decrypt(note.__value);
|
||||
return new_note;
|
||||
}
|
||||
|
@ -1,23 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./public",
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"sourceMap": true,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "h",
|
||||
"lib": [
|
||||
"es2015",
|
||||
"dom",
|
||||
"esnext"
|
||||
],
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": [
|
||||
"./src/types.d.ts",
|
||||
"./src/**/*.tsx",
|
||||
"./src/**/*.ts"
|
||||
]
|
||||
}
|
||||
"compilerOptions": {
|
||||
"outDir": "./public",
|
||||
"target": "ES2022",
|
||||
"module": "commonjs",
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"sourceMap": true,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "h",
|
||||
"lib": ["es2015", "dom", "esnext"],
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["./src/types.d.ts", "./src/**/*.tsx", "./src/**/*.ts"]
|
||||
}
|
||||
|
@ -1,76 +0,0 @@
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const Visualizer = require('webpack-visualizer-plugin');
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const config = require("./config.json");
|
||||
const url = require("url");
|
||||
|
||||
module.exports = {
|
||||
devServer: {
|
||||
host: "0.0.0.0", // Defaults to `localhost`
|
||||
open: false, // Open the page in browser,
|
||||
contentBase: path.join(__dirname, 'dist'),
|
||||
disableHostCheck: true,
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*"
|
||||
},
|
||||
watchOptions: {
|
||||
aggregateTimeout: 300,
|
||||
poll: 500
|
||||
},
|
||||
public: url.parse(config.callback_url).hostname
|
||||
},
|
||||
plugins: [
|
||||
new CopyWebpackPlugin([{
|
||||
from: "public"
|
||||
}]),
|
||||
new HtmlWebpackPlugin({
|
||||
title: 'SecureNotes',
|
||||
template: "./src/index.html"
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "[name].css",
|
||||
chunkFilename: "[id].css"
|
||||
}),
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: "static",
|
||||
openAnalyzer: false
|
||||
}),
|
||||
new Visualizer(),
|
||||
],
|
||||
entry: {
|
||||
main: "./src/index.tsx"
|
||||
},
|
||||
// Enable sourcemaps for debugging webpack's output.
|
||||
devtool: "eval",
|
||||
resolve: {
|
||||
// Add '.ts' and '.tsx' as resolvable extensions.
|
||||
extensions: [".webpack.js", ".web.js", ".ts", ".tsx", ".js", ".mjs"]
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/
|
||||
}, {
|
||||
test: /\.(png|jpg)$/,
|
||||
loader: "file-loader",
|
||||
}, {
|
||||
test: /\.(scss|css)$/,
|
||||
use: [
|
||||
"style-loader", // creates style nodes from JS strings
|
||||
MiniCssExtractPlugin.loader,
|
||||
"css-loader", // translates CSS into CommonJS
|
||||
"sass-loader" // compiles Sass to CSS, using Node Sass by default
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: ['preact-svg-loader'],
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user