Added NodeJS package with WebPack for some assets.

Moved JS files to WebPack system.

Created python script to watch both WebPack and Dotnet files simultaneously
This commit is contained in:
Harrison Deng 2021-06-06 17:46:01 -05:00
parent 7e240bd584
commit 54b1565537
19 changed files with 1952 additions and 15 deletions

24
scripts/watch_all.py Normal file
View File

@ -0,0 +1,24 @@
import os
import asyncio
import sys
SERVER_CSPROJ_DIR = "src/MultiShop/Server"
ASSET_WATCH_DIR = "src/MultiShop/Client/assets"
async def exec(cmd, path):
os.chdir(os.path.dirname(os.path.realpath(__file__)))
os.chdir(os.pardir)
os.chdir(path)
proc = await asyncio.create_subprocess_shell(
cmd,
stdout=sys.stdout,
stderr=sys.stderr,
)
await proc.wait()
async def main():
await asyncio.gather(exec("dotnet watch run", SERVER_CSPROJ_DIR), exec("npm run watch", ASSET_WATCH_DIR))
asyncio.run(main())

View File

@ -19,14 +19,11 @@ namespace MultiShop.Client
private IJSRuntime JS { get; set; }
[Inject]
private IHttpClientFactory HttpClientFactory {get; set;}
private IJSObjectReference localStorageManager;
private ICollection<RuntimeDependencyManager.Dependency> dependencies = new List<RuntimeDependencyManager.Dependency>();
protected override void OnInitialized()
{
base.OnInitialized();
dependencies.Add(new RuntimeDependencyManager.Dependency(typeof(IJSObjectReference), "JS Modules", (pHttp, http, auth, logger) => new ValueTask<object>(localStorageManager), "LocalStorageManager"));
dependencies.Add(new RuntimeDependencyManager.Dependency(typeof(IJSObjectReference), "JS Modules", async (pHttp, http, auth, logger) => await JS.InvokeAsync<IJSObjectReference>("import", "./js/Components/ComponentSupport.js"), "ComponentSupport"));
dependencies.Add(new RuntimeDependencyManager.Dependency(typeof(IReadOnlyDictionary<string, IShop>), "Shops", async (publicHttp, authenticatedHttp, auth, logger) => await (new ShopModuleLoader(publicHttp, logger)).GetShops()));
dependencies.Add(new RuntimeDependencyManager.Dependency(typeof(ApplicationProfile), "Application Profile", DownloadApplicationProfile));
}
@ -34,7 +31,6 @@ namespace MultiShop.Client
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
localStorageManager = await JS.InvokeAsync<IJSObjectReference>("import", "./js/LocalStorageManager.js");
}
private async ValueTask<object> DownloadApplicationProfile(HttpClient publicHttp, HttpClient http, AuthenticationState authState, ILogger logger)
@ -48,7 +44,7 @@ namespace MultiShop.Client
return await response.Content.ReadFromJsonAsync<ApplicationProfile>();
}
}
ApplicationProfile profile = await localStorageManager.InvokeAsync<ApplicationProfile>("retrieve", "ApplicationProfile");
ApplicationProfile profile = await JS.InvokeAsync<ApplicationProfile>("MultiShop.LocalStorageManager.retrieve", "ApplicationProfile");
if (profile != null) return profile;
return new ApplicationProfile();
}

View File

@ -0,0 +1,5 @@
@page "/assembler"
@code {
//TODO: Make a shopping list system where the user can use keywords for the system to automatically pull results from.
}

View File

@ -19,7 +19,10 @@ namespace MultiShop.Client.Pages
[Inject]
private LayoutStateChangeNotifier LayoutStateChangeNotifier { get; set; }
[Inject]
private IJSRuntime JS { get; set; }
[Inject]
private HttpClient Http { get; set; }
@ -67,11 +70,12 @@ namespace MultiShop.Client.Pages
public async ValueTask DisposeAsync()
{
AuthenticationState authenticationState = await AuthenticationStateTask;
if (authenticationState.User.Identity.IsAuthenticated) {
if (authenticationState.User.Identity.IsAuthenticated)
{
Logger.LogDebug($"User is authenticated. Attempting to save configuration to server.");
await Http.PutAsJsonAsync("Profile/Application", ApplicationProfile);
}
await RuntimeDependencyManager.Get<IJSObjectReference>("LocalStorageManager").InvokeVoidAsync("save", "ApplicationProfile", ApplicationProfile);
await JS.InvokeVoidAsync("MultiShop.LocalStorageManager.save", "ApplicationProfile", ApplicationProfile);
}
}
}

View File

@ -24,6 +24,9 @@ namespace MultiShop.Client.Pages
[Inject]
private HttpClient Http { get; set; }
[Inject]
private IJSRuntime JS {get; set;}
[CascadingParameter]
private Task<AuthenticationState> AuthenticationStateTask { get; set; }
@ -75,9 +78,8 @@ namespace MultiShop.Client.Pages
activeResultsProfile = await resultsProfileResponse.Content.ReadFromJsonAsync<ResultsProfile>();
}
}
IJSObjectReference localStorageManager = RuntimeDependencyManager.Get<IJSObjectReference>("LocalStorageManager");
if (activeSearchProfile == null) activeSearchProfile = await localStorageManager.InvokeAsync<SearchProfile>("retrieve", "SearchProfile");
if (activeResultsProfile == null) activeResultsProfile = await localStorageManager.InvokeAsync<ResultsProfile>("retrieve", "ResultsProfile");
if (activeSearchProfile == null) activeSearchProfile = await JS.InvokeAsync<SearchProfile>("MultiShop.LocalStorageManager.retrieve", "SearchProfile");
if (activeResultsProfile == null) activeResultsProfile = await JS.InvokeAsync<ResultsProfile>("MultiShop.LocalStorageManager.retrieve", "ResultsProfile");
if (activeSearchProfile == null) activeSearchProfile = new SearchProfile();
if (activeResultsProfile == null) activeResultsProfile = new ResultsProfile();
@ -258,9 +260,8 @@ namespace MultiShop.Client.Pages
await Http.PutAsJsonAsync("Profile/Search", activeSearchProfile);
await Http.PutAsJsonAsync("Profile/Results", activeResultsProfile);
}
IJSObjectReference localStorageManager = RuntimeDependencyManager.Get<IJSObjectReference>("LocalStorageManager");
await localStorageManager.InvokeVoidAsync("save", "SearchProfile", activeSearchProfile);
await localStorageManager.InvokeVoidAsync("save", "ResultsProfile", activeResultsProfile);
await JS.InvokeVoidAsync("MultiShop.LocalStorageManager.save", "SearchProfile", activeSearchProfile);
await JS.InvokeVoidAsync("MultiShop.LocalStorageManager.save", "ResultsProfile", activeResultsProfile);
}
public class Status

View File

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>MultiShop</title>
<base href="/" />
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />
<link href="MultiShop.Client.styles.css" rel="stylesheet" />
</head>
<body>
<div id="app">
<div class="d-flex flex-column align-items-center justify-content-center" style="width: 100vw; height: 100vh;">
<div class="my-2">
<div class="spinner-border text-secondary" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<div class="my-2 text-muted">
Loading...
</div>
</div>
</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="./js/app.dist.js"></script>
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>

View File

@ -0,0 +1 @@
//TODO: Add drop down component.

View File

@ -0,0 +1,40 @@
const APP_STORAGE_KEY = "MultiShop"
export let LocalStorageManager = {
save: (key, value) => {
try {
localStorage.setItem(APP_STORAGE_KEY + "/" + key, JSON.stringify(value));
} catch (error) {
console.warn("Failed to save value with key: " + key);
return false;
}
return true;
},
retrieve: (key) => {
let value = localStorage.getItem(APP_STORAGE_KEY + "/" + key);
if (value == null) return null;
try {
return JSON.parse(value);
} catch (error) {
if (error instanceof SyntaxError) {
console.warn("Unable to parse value for key \"" + key + "\". Removing.");
remove(key);
return null;
}
}
},
remove: (key) => {
localStorage.removeItem(APP_STORAGE_KEY + "/" + key);
},
clear: () => {
for (let i = 0; i < localStorage.length; i++) {
let name = localStorage.key(i);
if (name.startsWith(APP_STORAGE_KEY + "/")) {
localStorage.removeItem(name);
}
}
}
}

View File

@ -0,0 +1,2 @@
export * from "./Persistence/LocalStorageManager";
export * from "./Components/ComponentSupport";

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
{
"private": "true",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"watch": "webpack --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.14.3",
"babel-loader": "^8.2.2",
"css-loader": "^5.2.6",
"style-loader": "^2.0.0",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.0"
},
"dependencies": {
"bootstrap": "^5.0.1"
}
}

View File

@ -0,0 +1,26 @@
const path = require('path');
module.exports = {
entry: './js/app.js',
mode: "development",
output: {
filename: 'app.dist.js',
path: path.resolve(__dirname, '../wwwroot/js'),
library: "MultiShop"
},
module: {
rules: [
{ test: /\.(js|jsx)$/, use: "babel-loader" },
{test: /\.(scss)$/, use: ["style-loader", "css-loader", {
loader: "postcss-loader",
options: {
plugins: function () {
return [require("autoprefixer")];
}
}
},
"sass-loader"
]}
]
},
};

View File

@ -49,7 +49,10 @@ nav.bg-dark {
.bg-dark input:disabled {
background-color: #36383C;
color: whitesmoke;
}
.bg-dark input:disabled::placeholder {
color: gray;
}
.bg-dark input::placeholder {

View File

@ -31,6 +31,7 @@
<a class="dismiss">🗙</a>
</div>
<script src="./js/app.dist.js"></script>
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
</body>

View File

@ -0,0 +1 @@
//TODO: Add drop down component.

View File

@ -0,0 +1,121 @@
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
var MultiShop;
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./js/Components/ComponentSupport.js":
/*!*******************************************!*\
!*** ./js/Components/ComponentSupport.js ***!
\*******************************************/
/***/ (() => {
eval("//TODO: Add drop down component.\n\n//# sourceURL=webpack://MultiShop/./js/Components/ComponentSupport.js?");
/***/ }),
/***/ "./js/Persistence/LocalStorageManager.js":
/*!***********************************************!*\
!*** ./js/Persistence/LocalStorageManager.js ***!
\***********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"LocalStorageManager\": () => (/* binding */ LocalStorageManager)\n/* harmony export */ });\nconst APP_STORAGE_KEY = \"MultiShop\";\nlet LocalStorageManager = {\n save: (key, value) => {\n try {\n localStorage.setItem(APP_STORAGE_KEY + \"/\" + key, JSON.stringify(value));\n } catch (error) {\n console.warn(\"Failed to save value with key: \" + key);\n return false;\n }\n\n return true;\n },\n retrieve: key => {\n let value = localStorage.getItem(APP_STORAGE_KEY + \"/\" + key);\n if (value == null) return null;\n\n try {\n return JSON.parse(value);\n } catch (error) {\n if (error instanceof SyntaxError) {\n console.warn(\"Unable to parse value for key \\\"\" + key + \"\\\". Removing.\");\n remove(key);\n return null;\n }\n }\n },\n remove: key => {\n localStorage.removeItem(APP_STORAGE_KEY + \"/\" + key);\n },\n clear: () => {\n for (let i = 0; i < localStorage.length; i++) {\n let name = localStorage.key(i);\n\n if (name.startsWith(APP_STORAGE_KEY + \"/\")) {\n localStorage.removeItem(name);\n }\n }\n }\n};\n\n//# sourceURL=webpack://MultiShop/./js/Persistence/LocalStorageManager.js?");
/***/ }),
/***/ "./js/app.js":
/*!*******************!*\
!*** ./js/app.js ***!
\*******************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"LocalStorageManager\": () => (/* reexport safe */ _Persistence_LocalStorageManager__WEBPACK_IMPORTED_MODULE_0__.LocalStorageManager)\n/* harmony export */ });\n/* harmony import */ var _Persistence_LocalStorageManager__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Persistence/LocalStorageManager */ \"./js/Persistence/LocalStorageManager.js\");\n/* harmony import */ var _Components_ComponentSupport__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Components/ComponentSupport */ \"./js/Components/ComponentSupport.js\");\n/* harmony import */ var _Components_ComponentSupport__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_Components_ComponentSupport__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony reexport (unknown) */ var __WEBPACK_REEXPORT_OBJECT__ = {};\n/* harmony reexport (unknown) */ for(const __WEBPACK_IMPORT_KEY__ in _Components_ComponentSupport__WEBPACK_IMPORTED_MODULE_1__) if([\"default\",\"LocalStorageManager\"].indexOf(__WEBPACK_IMPORT_KEY__) < 0) __WEBPACK_REEXPORT_OBJECT__[__WEBPACK_IMPORT_KEY__] = () => _Components_ComponentSupport__WEBPACK_IMPORTED_MODULE_1__[__WEBPACK_IMPORT_KEY__]\n/* harmony reexport (unknown) */ __webpack_require__.d(__webpack_exports__, __WEBPACK_REEXPORT_OBJECT__);\n\n\n\n//# sourceURL=webpack://MultiShop/./js/app.js?");
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = (module) => {
/******/ var getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module can't be inlined because the eval devtool is used.
/******/ var __webpack_exports__ = __webpack_require__("./js/app.js");
/******/ MultiShop = __webpack_exports__;
/******/
/******/ })()
;