Mobx statechange not detected - mobx

I have a small simple setup. With mobx and preact.
class AppStore {
loadingobjects = true;
constructor() {
makeObservable(this, {
loadingobjects: observable,
});
this.fetchCommonObjects();
}
fetchCommonObjects = () => {
window
.fetch(url)
.then((res) => res.json())
.then((json) => {
/* data processing */
this.loadingobjects = false;
});
};
}
export const AppStoreContext = createContext();
function AppStoreProvider({ children }) {
return (
<AppStoreContext.Provider value={new AppStore()}>
{children}
</AppStoreContext.Provider>
);
}
export default AppStoreProvider;
export default function useAppStore() {
return useContext(AppStoreContext);
}
const List = observer(() => {
const store = useAppStore();
if (store.loadingobjects) {
return <div class="ui active centered inline loader"></div>;
} else {
return (page content);
}
});
problem is that store.loadingobjects Is always false. Seems like im doing something wrong but i cant put my finger on it...
What am i missing or doing wrong?
Edit addding my configs:
package.json
{
"name": "project",
"version": "0.0.2",
"license": "MIT",
"scripts": {
"start": "set NODE_ENV=dev && webpack serve --mode=development",
"build": "set NODE_ENV=production && webpack -p",
},
"devDependencies": {
"#babel/core": "^7.20.12",
"#babel/plugin-transform-runtime": "^7.19.6",
"#babel/preset-env": "^7.20.2",
"#babel/preset-react": "^7.18.6",
"babel-loader": "^9.1.2",
"babel-plugin-import": "^1.13.6",
"html-webpack-plugin": "^5.5.0",
"surge": "^0.19.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.11.1"
},
"dependencies": {
"#babel/polyfill": "^7.12.1",
"mobx": "^6.7.0",
"mobx-react": "^7.6.0",
"preact": "^10.11.3"
}
}
webpack.config.js
const path = require('path');
const isProd = (process.env.NODE_ENV === 'production');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
//input
entry: ["#babel/polyfill",'./src'],
resolve: {
alias:{
"react": "preact/compat",
"react-dom": "preact/compat",
"react/jsx-runtime": "preact/jsx-runtime"
}
},
//output
output: {
path : path.join(__dirname, 'build'),
filename : 'bundle.js'
},
//transformations
module: {
rules : [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
}
]
},
//sourcemaps
devtool: 'source-map',
plugins: [new HtmlWebpackPlugin({
template: './src/index.html',
favicon: "./src/favicon.ico"
})],
//server
devServer: {
compress: true,
historyApiFallback: true
}
}
.babelrc
{
"presets": ["#babel/preset-react", ["#babel/preset-env", {"useBuiltIns": "usage",}]],
"plugins": [
["#babel/plugin-transform-runtime"],
[
"#babel/plugin-transform-react-jsx",
{
"pragma": "h",
"pragmaFrag": "Fragment"
}
]
]
}

I found the issue. I started cutting the components into smaller pieces and then adding and removing them into the component hierarchy until i found the component causing the issue. It turned out that i had done onClick={method()} and this was changeing state causing the endless rerenders.

Related

Nuxt, Vue, RefreshToken => Uncaught (in promise) TypeError: Cannot read property 'protocol' of undefined => Axios plugin, Axios Interceptors

my goal is to refresh the token after catching the 401 status code and the "token expired" message in my interceptor on the response ...
What are they doing wrong?
I'm using nuxt, vue, axios. Please help!
Uncaught (in promise) TypeError: Cannot read property 'protocol' of
undefined
it sends me back to that code:
#/plugins/axios.js:
import Vue from 'vue';
import axios from 'axios';
axios.interceptors.response.use((response) => {
console.debug("AXIOS.JS plugin => response: ", response);
return response;
}, function (error) {
console.debug("AXIOS.JS plugin => error: ", error);
return Promise.reject(error);
});
Vue.use(axios);
package.json:
{
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate"
},
"dependencies": {
"#nuxtjs/axios": "^5.13.1",
"#nuxtjs/composition-api": "^0.24.7",
"#nuxtjs/dotenv": "^1.4.1",
"#nuxtjs/proxy": "^2.1.0",
"#nuxtjs/pwa": "^3.3.5",
"#vue/composition-api": "^1.0.0-rc.13",
"core-js": "^3.9.1",
"nuxt": "^2.15.6",
"vue-multiselect": "^2.1.6",
"vue2-datepicker": "^3.9.1"
},
"devDependencies": {
"#nuxtjs/tailwindcss": "^4.1.2",
"autoprefixer": "^10.2.5",
"postcss": "^8.3.0",
"tailwindcss": "^2.1.2"
}
}
nuxt.config.js
const routes = require('./routes/index.js')
export default {
// Global page headers: https://go.nuxtjs.dev/config-head
head: {
title: 'Fokser',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
],
script: [
{
//src: "https://skrypt-cookies.pl/id/d6458d5064c23515.js",
//src: "https://skrypt-cookies.pl/id/69205d8cab854dc2.js",
body: true,
},
],
},
// Global CSS: https://go.nuxtjs.dev/config-css
css: [
'#/static/css/styles.css',
],
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
{
src: "#/plugins/filters.js",
src: "#/plugins/axios.js",
}
],
// Auto import components: https://go.nuxtjs.dev/config-components
components: true,
// Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules
buildModules: [
// https://go.nuxtjs.dev/tailwindcss
'#nuxtjs/tailwindcss',
'#nuxtjs/composition-api/module'
],
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
// https://go.nuxtjs.dev/axios
'#nuxtjs/axios',
// https://go.nuxtjs.dev/pwa
'#nuxtjs/pwa',
'#nuxtjs/proxy',
'#nuxtjs/dotenv'
],
// Axios module configuration: https://go.nuxtjs.dev/config-axios
axios: {
proxy: true
},
// PWA module configuration: https://go.nuxtjs.dev/pwa
pwa: {
manifest: {
lang: 'en'
}
},
// Build Configuration: https://go.nuxtjs.dev/config-build
build: {
},
proxy: {
'/api/': {
target: process.env.VUE_APP_ROOT_API,
pathRewrite: { '^/api': '' }
}
},
router: {
extendRoutes(nuxtRoutes, resolve) {
routes.forEach((route) => {
nuxtRoutes.push({
name: route.name,
path: route.path,
component: resolve(__dirname, route.component)
})
})
}
}
}
This occurs at main page (localhost):
besides, I am making a request to api like:
loadUserInfo({ commit }) {
let token = localStorage.getItem("auth_token");
let userId = localStorage.getItem("id");
commit("setUserToken", token);
commit("setUserId", userId);
if (userId && token) {
this.$axios.get(`api/accounts/userName/${userId}`)
.then((res) => {
if (res.status === 200) {
commit("setUserName", res.data.userName);
}
})
.catch(err => {
console.debug("[authorize.js LoadUserInfo], errors: ", err);
})
}
},
async getRecords({commit}, request) {
let config = {
params: {
recordType: request.recordType,
limit: limit
},
}
return await this.$axios.get(`/api/records/getRecords`, config);
}
loadAll({ commit }, request) {
this.$axios.get(`/api/records/all`, request)
.then((res) => {
if (res.status === 200) {
commit('setRecords', res.data);
}
});
},
I don't know where is the problem... :(

vue.runtime.esm-browser.js does not render Vue 3 components

I created a vue 3 project using Vue cli. I am using a webpack config to manage my build. When I point my vue bundle to vue.runtime.esm-browser.js, then I get a warning in browser console. "[Vue warn]: Component provided template option but runtime compilation is not supported in this build of Vue. Use "vue.esm-browser.js" instead."
When I checked the docs, it was mentioned as "vue-loader" plugin converts the html template to render functions. Looks like I am missing something which is needed to webpack.
Entry file : main.js
import { createApp } from "vue";
import corecomponentA from "../core/components/corecomponentA.vue";
createApp({
components: {
"core-component-a": corecomponentA,
},
}).mount("#app");
Webpack.config.js
var path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const { VueLoaderPlugin } = require("vue-loader");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
.BundleAnalyzerPlugin;
const WebpackBar = require("webpackbar");
module.exports = (env, options) => {
const devMode = options.mode != "production";
return {
entry: {
"vue-bundle-store": "./src/entry/main.js",
},
output: {
path: path.resolve(
__dirname,
"./../ui.clientlibs/src/js/"
),
filename: "[name].js",
chunkFilename: "[name].js",
publicPath: process.env.BASE_URL,
},
module: {
rules: [
{
enforce: "pre",
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
},
{
test: /\.vue$/,
loader: "vue-loader",
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: "/node_modules/",
query: {
presets: ["#babel/preset-env"],
},
},
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: { babelrc: true },
},
{
loader: "ts-loader",
options: { appendTsSuffixTo: [/\.vue$/] },
},
],
},
],
},
stats: {
colors: true,
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor-bundle",
chunks: "all",
},
},
},
minimizer: !devMode
? [
new UglifyJsPlugin({
sourceMap: false,
uglifyOptions: {
chunkFilter: (chunk) => {
if (chunk.name === "vendor-bundle") {
return false;
}
return true;
},
compress: {
drop_console: true,
},
mangle: {
reserved: ["vueIns", "args", "el"],
},
},
}),
]
: [],
},
devtool: "source-map",
plugins: [
new CleanWebpackPlugin(),
new VueLoaderPlugin(),
new WebpackBar(),
new BundleAnalyzerPlugin({
analyzerPort: 4000,
openAnalyzer: false,
analyzerMode: "static",
}),
] ,
resolve: {
extensions: [".ts", ".js", ".vue", ".json"],
alias: {
vue: devMode ? "vue/dist/vue.runtime.esm-browser.js" : "vue/dist/vue.runtime.esm-browser.prod.js"
}
}
};
};
coreComponentA.vue
<script lang="ts">
import { h, ref, reactive } from "vue";
export default {
setup() {
const str = ref("Core component B");
const object = reactive({ foo: "bar" });
return () => h("div", [str.value, object.foo]);
}
};
</script>
package.json
{
"name": "vue3.test",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"lint": "vue-cli-service lint",
"analyze-bundle": "webpack-bundle-analyzer stats.json",
"bundle": "webpack --mode=production --env.production --config webpack.config.js",
"bundle-dev": "webpack --mode=development --env.production=false --config webpack.config.js",
"stats": "webpack --mode=production --env.production --config webpack.config.js --profile --json > stats.json"
},
"dependencies": {
"vue": "^3.0.2"
},
"devDependencies": {
"#types/jest": "^24.0.19",
"#typescript-eslint/eslint-plugin": "^2.33.0",
"#typescript-eslint/parser": "^2.33.0",
"#vue/cli-plugin-babel": "~4.5.0",
"#vue/cli-plugin-eslint": "~4.5.0",
"#vue/cli-plugin-typescript": "~4.5.0",
"#vue/cli-plugin-unit-jest": "~4.5.0",
"#vue/cli-service": "~4.5.0",
"#vue/compiler-sfc": "^3.0.2",
"#vue/eslint-config-prettier": "^6.0.0",
"#vue/eslint-config-typescript": "^5.0.2",
"#vue/test-utils": "^2.0.0-0",
"clean-webpack-plugin": "^3.0.0",
"core-js": "^3.6.5",
"eslint": "^6.7.2",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-vue": "^7.0.0-0",
"html-webpack-plugin": "^3.2.0",
"prettier": "^1.19.1",
"typescript": "~3.9.3",
"uglifyjs-webpack-plugin": "^2.2.0",
"vue-jest": "^5.0.0-0",
"vue-loader": "^16.0.0-beta.8",
"webpack-cli": "^3.3.10",
"webpackbar": "^4.0.0"
}
}
babel.config.js
module.exports = {
ignore: [/\/core-js/],
presets: [
[
"#babel/preset-env",
{ modules: false, useBuiltIns: "usage", corejs: "3.6.5" },
],
],
overrides: [
{
test: "./node_modules",
sourceType: "unambiguous",
},
],
};
Usage of my component in a html file
<div id="app">
<core-component-a></core-component-a>
</div>
The component is not rendered in browser. Instead the below message is displayed.
VM211871:1 [Vue warn]: Component provided template option but runtime compilation is not supported in this build of Vue. Use "vue.esm-browser.js" instead.
at <App>
vue-loader converts the html template to render function only in SFC's (Sinle File Components) - .vue files (as you can tell from vue rule in Webpack config) - and only templates provided in <template></template> block of SFC
But you have a template in your HTML file - content of <div id="app"> is essentially Vue template. Runtime + Compiler vs. Runtime-only
Docs vue.esm-bundler.js: includes the runtime compiler. Use this if you are using a bundler but still want runtime template compilation (e.g. in-DOM templates or templates via inline JavaScript strings - component template option).
Also if you using Webpack, you should use "bundler" version of Vue
Webpack.config.js
alias: {
vue: "vue/dist/vue.esm-bundler.js"
}
...you don't need to switch minified/dev bundle because Webpack will (when configured correctly) optimize Vue code same way as your own code..
Also, pay attention to this sentence in the docs: Leaves prod/dev branches with process.env.NODE_ENV guards (must be replaced by bundler)
NODE_ENV is conventionally used to define the environment type and is used by Vue to decide what code to include...
Note
I don't really understand why are You using your own Webpack config for project created with Vue CLI when whole point of Vue CLI is to manage webpack config for you and offers plenty of options to customize it...doesn't make any sense
If you are using Vite, add the alias 'vue': 'vue/dist/vue.esm-bundler' to vite.config.js
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'vue': 'vue/dist/vue.esm-bundler',
},
}
})
you just have to replace on Webpack.config.js
alias: {
vue: devMode ? "vue/dist/vue.runtime.esm-browser.js" : "vue/dist/vue.runtime.esm-browser.prod.js"
}
With
vue: "vue/dist/vue.esm-bundler.js"
This works for me.

Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 1 Error with React, Babel and Webpack

I am building a CRUD web application using Webpack, Express, Epilogue, Sequelize, Sqlite3 and React. After setting up Webpack and Babel, I can add entries to the database but not retrieve entries. When I add an entry, if I look at http://localhost:3000/blogposts (one of my endpoints) the page is blank, but in the server output I see my entries get added.
server output in the console
To retrieve entries from the database I use:
getPosts = async () => {
const response = await fetch('/blogposts');
const data = await response.json();
data.forEach(item => item.editMode = false);
this.setState({ data })
}
And I get the error: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 1
full error message
I assume this is an error with babel/webpack and await/async.
my webpack.config.js:
const path = require("path")
const HtmlWebPackPlugin = require("html-webpack-plugin")
module.exports = {
entry: {
main: './src/index.js'
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/',
filename: '[name].js'
},
target: 'web',
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
},
]
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./src/index.html",
excludeChunks: [ 'server' ]
})
],
resolve: {
extensions: ["*",".js", ".jsx", "json"],
alias: {
'components': path.resolve(__dirname, '/components')
}
},
}
my webpackserver.config.js:
const path = require('path')
const nodeExternals = require('webpack-node-externals')
module.exports = {
entry: {
server: './src/server/server.js',
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/',
filename: '[name].js'
},
target: 'node',
resolve: {
extensions: ['.js', '.jsx'],
alias: {
'components': path.resolve(__dirname, '/components')
}
},
node: {
__dirname: false,
__filename: false,
},
externals: [nodeExternals()],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
}
my server.js:
import path from 'path'
import express from 'express'
require('dotenv').config();
const cors = require('cors');
const bodyParser = require('body-parser');
const session = require('express-session');
const { ExpressOIDC } = require('#okta/oidc-middleware');
const Sequelize = require('sequelize');
const epilogue = require('epilogue'), ForbiddenError = epilogue.Errors.ForbiddenError;
const port = process.env.PORT || 3000
const app = express(),
DIST_DIR = __dirname,
HTML_FILE = path.join(DIST_DIR, '/src/index.html')
app.use(express.static(DIST_DIR))
app.get('*', (req, res) => {
res.sendFile(HTML_FILE)
})
// session support is required to use ExpressOIDC
app.use(session({
secret: process.env.RANDOM_SECRET_WORD,
resave: true,
saveUninitialized: false
}));
const oidc = new ExpressOIDC({
issuer: `${process.env.OKTA_ORG_URL}/oauth2/default`,
client_id: process.env.OKTA_CLIENT_ID,
client_secret: process.env.OKTA_CLIENT_SECRET,
redirect_uri: process.env.REDIRECT_URL,
scope: 'openid profile',
routes: {
callback: {
path: '/authorization-code/callback',
defaultRedirect: '/admin'
}
}
});
// ExpressOIDC will attach handlers for the /login and /authorization-code/callback routes
app.use(oidc.router);
app.use(cors());
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'src')));
app.get('/home', (req, res) => {
res.sendFile(path.join(__dirname, './home.html'));
});
app.get('/admin', oidc.ensureAuthenticated(), (req, res) => {
res.sendFile(path.join(__dirname, './admin.html'));
});
app.get('/logout', (req, res) => {
req.logout();
res.redirect('/home');
});
console.log("redirect");
app.get('/', (req, res) => {
res.redirect('/home');
});
// //for each blog post
app.get('/lifestyle/:title', function (req, res) {
res.send('Blogpost template here!')
})
const database = new Sequelize({
dialect: 'sqlite',
storage: './db.sqlite',
operatorsAliases: false,
});
const Post = database.define('posts', {
title: Sequelize.STRING,
content: Sequelize.TEXT,
});
const blogPost = database.define('blogposts', {
title: Sequelize.STRING,
content: Sequelize.TEXT,
published: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false,
},
});
const test = database.define('test', {
title: Sequelize.STRING,
content: Sequelize.TEXT,
});
epilogue.initialize({ app, sequelize: database });
const PostResource = epilogue.resource({
model: Post,
endpoints: ['/posts', '/posts/:id'],
});
const blogPostResource = epilogue.resource({
model: blogPost,
endpoints: ['/blogposts', '/blogposts/:id'],
});
PostResource.all.auth(function (req, res, context) {
return new Promise(function (resolve, reject) {
resolve(context.continue);
})
});
database.sync().then(() => {
oidc.on('ready', () => {
app.listen(port, () => console.log(`My Blog App listening on port ${port}!`))
});
});
oidc.on('error', err => {
// An error occurred while setting up OIDC
console.log("oidc error: ", err);
});
my package.json:
{
"name": "blog",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"build": "rm -rf dist && webpack --mode development --config webpackserver.config.js && webpack --mode development",
"start": "node ./dist/server.js"
},
"proxy": "http://localhost:3000",
"author": "",
"license": "ISC",
"dependencies": {
"#okta/oidc-middleware": "1.0.2",
"D": "1.0.0",
"babel-polyfill": "6.26.0",
"babel-preset-es2015": "6.24.1",
"babel-preset-stage-0": "6.24.1",
"babel-runtime": "6.26.0",
"body-parser": "1.18.3",
"cors": "2.8.5",
"dotenv": "6.2.0",
"epilogue": "0.7.1",
"express": "4.16.4",
"express-session": "1.15.6",
"fibers": "4.0.2",
"node-sass": "4.13.0",
"rc": "1.2.8",
"sass": "1.23.7",
"sequelize": "4.44.3",
"sqlite3": "4.1.0",
"webpack-isomorphic-tools": "3.0.6"
},
"devDependencies": {
"#babel/core": "7.7.5",
"#babel/plugin-proposal-class-properties": "7.7.4",
"#babel/plugin-transform-runtime": "7.7.6",
"#babel/preset-env": "7.7.6",
"#babel/preset-react": "7.7.4",
"#material-ui/core": "4.7.2",
"#material-ui/icons": "4.5.1",
"babel-loader": "8.0.6",
"babel-plugin-transform-runtime": "6.23.0",
"babel-preset-env": "1.7.0",
"css-loader": "3.3.2",
"file-loader": "5.0.2",
"grommet": "2.9.0",
"html-loader": "0.5.5",
"html-webpack-plugin": "3.2.0",
"json-loader": "0.5.7",
"nodemon": "1.18.9",
"nodemon-webpack-plugin": "4.2.2",
"react": "16.12.0",
"react-dom": "16.12.0",
"react-router-dom": "5.1.2",
"sass-loader": "8.0.0",
"style-loader": "1.0.1",
"styled-components": "4.4.1",
"typeface-roboto": "0.0.75",
"webpack": "4.41.2",
"webpack-cli": "3.3.10",
"webpack-node-externals": "1.7.2"
}
}
my .babelrc"
{
"presets": [
"#babel/preset-env",
"#babel/react"
],
"plugins" : [
"#babel/plugin-proposal-class-properties",
"#babel/plugin-transform-runtime"
]
}

Webpack 2 bundle typescript files with same namespace into a single file

I am new to Webpack and bundling typescript files into a single file. I got the following setup where I would like to achieve a single JS files with all my typescript bundled.
tsconfig.json:
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"noEmitOnError": true,
"noImplicitAny": false,
"removeComments": true,
"sourceMap": true,
"target": "es6",
"moduleResolution": "node"
},
"exclude": [
"node_modules",
"libs"
]
}
Webpack.config.js
var path = require("path");
const { CheckerPlugin } = require('awesome-typescript-loader');
const config = {
entry: {
Bootstrap: "./Bootstrapper.ts"
},
output: {
//output file naming conventions https://webpack.js.org/configuration/output/#output-filename when having more different configs with outputs
filename: "[name].bundle.js",
path: path.resolve(__dirname, "wwwroot/dist")
},
context: path.resolve(__dirname, "App"),
devtool: "inline-source-map",
module: {
rules: [
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader"
}
]
},
plugins: [
new CheckerPlugin()
]
}
module.exports = config;
Bootstrap typescript file where I incude some node_module that actually work. JQuery works for instance. But If I try to use the class and subclasses that I use from a single namespace I walk against a wall.
Bootstrapper.ts
import * as $ from "jquery";
import * as Konva from "konva";
import * as SignalR from "#aspnet/signalr";
import * as ko from "knockout";
//How do I use these classes that are in different files
import App = Project.Web.Core.App;
$("document").ready(() => {
let app = new App();
alert("This works if I leave the App reference out!");
});
This is the App.ts that I try to use (import App = Project.Web.Core.App;)
namespace Project.Web.Core {
export class App {
pageId: number = 0;
pageRequestId: string = "";
//drawingManager = new Managers.KonvaDrawManager();
signalRmanager = new Managers.SignalRmanager("");
constructor() {
$("document").ready(() => {
this.pageId = $("#container").data("pageid");
this.pageRequestId = $("#container").data("pagerequestid");
this.signalRmanager.pageRequestId = this.pageRequestId;
//this.signalRmanager.setupSignalRConnection(this.drawingManager);
this.loadCanvasData();
});
window.onresize = () => {
//this.drawingManager.rescale();
};
window.onunload = () => {
this.signalRmanager.notifyPageUnloaded();
}
}
loadCanvasData() {
this.pageId = $("#container").data("pageid");
$.get({
dataType: "json",
url: `api/page/${this.pageId}/stage`,
success: (data: any) => {
//this.drawingManager.initializeStage(data);
},
complete: (data: any) => {
if (data.status === 200) {
this.signalRmanager.notifyPageLoaded();
}
}
});
}
}
}
Packages I use
{
"name": "Project.Web_core",
"private": true,
"version": "0.0.0",
"scripts": {
"build": "./node_modules/.bin/webpack -d",
"build:prod": "./node_modules/.bin/webpack -p",
"watch": "./node_modules/.bin/webpack --watch",
"dev": "./node_modules/.bin/webpack-dev-server"
},
"devDependencies": {
"#types/jquery": "^3.3.1",
"#types/knockout": "^3.4.53",
"#types/knockout.mapping": "^2.0.33",
"#types/webpack-env": "1.13.5",
"aspnet-prerendering": "^3.0.1",
"aspnet-webpack": "^2.0.3",
"awesome-typescript-loader": "^5.0.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"event-source-polyfill": "0.0.12",
"json-loader": "0.5.7",
"node-sass": "^4.8.3",
"sass-loader": "^6.0.7",
"style-loader": "0.20.1",
"typescript": "2.7.1",
"uglifyjs-webpack-plugin": "^1.2.4",
"webpack": "^4.5.0",
"webpack-cli": "^2.0.14",
"webpack-dev-middleware": "^3.1.2",
"webpack-dev-server": "^3.1.3",
"webpack-merge": "4.1.1"
},
"dependencies": {
"#aspnet/signalr": "^1.0.0-preview1-update1",
"es5-shim": "^4.5.10",
"es6-shim": "^0.35.3",
"jquery": "3.3.1",
"knockout": "^3.4.2",
"knockout-mapping": "^2.6.0",
"konva": "^2.0.2",
"watchpack": "^1.4.0"
}
}
I hope someone can help me out clearify my wrong way of thinking.
There are several things:
Typescript config, you can copy. With your types
change import export and remove namespace
export class App { ... }
import { App } from '/path/to/your/file';
class needs a destroyer
and finally in webpack.config.js you can set properties
entry: {
Bootstrap: "./Bootstrapper.ts",
namespace: "./path-to-your-namespace.ts",
anotherNamespace: "./path-to-your-anotherNamespace.ts"
},
resolve: {
extensions: ['.js', '.ts', '.json']
}

.bind no longer working after upgrading to new Aurelia webpack plugins

I'm trying to update my Aurelia project that uses webpack so I can require .scss files in my templates. I've looked at the Aurelia Skeleton project for webpack and have followed this guide to come up with my webpack.config which is listed below. I have also included my package.json file.
I am able to load styles now, but have come across a perplexing issue. None of the my bind statements work anymore. The code itself didn't change and was working fine before this update attempt. I tried using two-way, one-way, etc, but that didn't work either. The #bindable property is always undefined.
<my-custom-element value.bind="something"></my-custom-element>
In MyCustomElement, value is always undefined although something is set properly.
I have tried walking back the package versions and I think it has to do with aurelia-bootstrapper, but I'm not sure.
I'm out of ideas on how to debug this issue. Any help would be much appreciated.
webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const DashboardPlugin = require('webpack-dashboard/plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const { AureliaPlugin, ModuleDependenciesPlugin } = require('aurelia-webpack-plugin');
const { optimize: { CommonsChunkPlugin }, ProvidePlugin } = require('webpack')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const project = require('./package.json');
// config helpers:
const ensureArray = (config) => config && (Array.isArray(config) ? config : [config]) || []
const when = (condition, config, negativeConfig) =>
condition ? ensureArray(config) : ensureArray(negativeConfig)
// primary config:
const title = 'Radar';
const outDir = path.resolve(__dirname, 'dist');
const srcDir = path.resolve(__dirname, 'src');
const nodeModulesDir = path.resolve(__dirname, 'node_modules');
const baseUrl = '/';
// If not done this way the plugin will try to load when only a build is required and cause it to hang.
const addDashboardPlugin = process.env.npm_lifecycle_event === 'webpack' ? [] : [new DashboardPlugin({
port: 3333
})];
const metadata = {
port: process.env.WEBPACK_PORT || 9000,
host: process.env.WEBPACK_HOST || 'localhost'
};
const cssRules = [
{ loader: 'css-loader' },
{
loader: 'postcss-loader',
options: { plugins: () => [require('autoprefixer')({ browsers: ['last 2 versions'] })] }
}
]
module.exports = ({ production, server, extractCss, coverage } = {}) => ({
resolve: {
extensions: ['.js'],
modules: [srcDir, 'node_modules'],
},
entry: {
app: ['aurelia-bootstrapper'],
aurelia: Object.keys(project.dependencies).filter(dep => dep.startsWith('aurelia-')),
vendor: Object.keys(project.dependencies).filter(dep => !dep.startsWith('aurelia-'))
},
devtool: production ? 'source-map' : 'inline-source-map',
output: {
path: outDir,
publicPath: baseUrl,
filename: production ? '[name].[chunkhash].bundle.js' : '[name].[hash].bundle.js',
sourceMapFilename: production ? '[name].[chunkhash].bundle.map' : '[name].[hash].bundle.map',
chunkFilename: production ? '[name].[chunkhash].chunk.js' : '[name].[hash].chunk.js',
},
devServer: {
contentBase: outDir,
// serve index.html for all 404 (required for push-state)
historyApiFallback: true,
port: metadata.port,
host: metadata.host,
watchOptions: {
aggregateTimeout: 300,
poll: 1000
}
},
module: {
rules: [
{
test: /\.scss$/i,
issuer: [{ not: [{ test: /\.html$/i }] }],
loaders: ['style-loader', 'css-loader?sourceMap', 'sass-loader?sourceMap']
},
{
test: /\.scss$/i,
issuer: [{ test: /\.html$/i }],
loaders: ['css-loader?sourceMap', 'sass-loader?sourceMap']
},
// CSS required in JS/TS files should use the style-loader that auto-injects it into the website
// only when the issuer is a .js/.ts file, so the loaders are not applied inside html templates
{
test: /\.css$/i,
issuer: [{ not: [{ test: /\.html$/i }] }],
use: extractCss ? ExtractTextPlugin.extract({
fallback: 'style-loader',
use: cssRules,
}) : ['style-loader', ...cssRules],
},
{
test: /\.css$/i,
issuer: [{ test: /\.html$/i }],
// CSS required in templates cannot be extracted safely
// because Aurelia would try to require it again in runtime
use: cssRules,
},
{ test: /\.html$/i, loader: 'html-loader' },
{
test: /\.js$/i, loader: 'babel-loader', exclude: nodeModulesDir,
options: coverage ? { sourceMap: 'inline', plugins: ['istanbul'] } : {},
},
{ test: /\.json$/i, loader: 'json-loader' },
// use Bluebird as the global Promise implementation:
{ test: /[\/\\]node_modules[\/\\]bluebird[\/\\].+\.js$/, loader: 'expose-loader?Promise' },
// embed small images and fonts as Data Urls and larger ones as files:
{ test: /\.(png|gif|jpg|cur)$/i, loader: 'url-loader', options: { limit: 8192 } },
{ test: /\.woff2(\?v=[0-9]\.[0-9]\.[0-9])?$/i, loader: 'url-loader', options: { limit: 10000, mimetype: 'application/font-woff2' } },
{ test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/i, loader: 'url-loader', options: { limit: 10000, mimetype: 'application/font-woff' } },
// load these fonts normally, as files:
{ test: /\.(ttf|eot|svg|otf)(\?v=[0-9]\.[0-9]\.[0-9])?$/i, loader: 'file-loader' },
]
},
plugins: [
new AureliaPlugin(),
new ModuleDependenciesPlugin({
'aurelia-dialog': ['./ai-dialog', './ai-dialog-header', './ai-dialog-footer', './ai-dialog-body',
'./attach-focus', './dialog-configuration', './dialog-controller', './dialog-options', './dialog-renderer',
'./dialog-result', './dialog-service', './lifecycle', './renderer'],
'aurelia-chart': ['./elements/chart-element', './attributes/chart-attribute', './observers/model-observer']
}),
new ProvidePlugin({
'Promise': 'bluebird'
}),
new HtmlWebpackPlugin({
template: 'index.ejs',
minify: production ? {
removeComments: true,
collapseWhitespace: true
} : undefined,
metadata: {
title, server, baseUrl
},
}),
new CopyWebpackPlugin([
{ from: 'src/config', to: 'config' },
{ from: 'styles/img', to: 'img' }
]),
...when(extractCss, new ExtractTextPlugin({
filename: production ? '[contenthash].css' : '[id].css',
allChunks: true,
})),
...when(production, new CommonsChunkPlugin({
name: 'common'
})),
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.scss$/i,
cssProcessor: require('cssnano'),
cssProcessorOptions: { discardComments: { removeAll: true } },
canPrint: true
})
].concat(addDashboardPlugin)
})
package.json
"dependencies": {
"aurelia-animator-css": "^1.0.0",
"aurelia-application-insights": "^1.0.0",
"aurelia-binding": "^1.2.0",
"aurelia-bootstrapper": "^2.1.1",
"aurelia-chart": "^0.2.6",
"aurelia-configuration": "1.0.17",
"aurelia-dependency-injection": "^1.3.1",
"aurelia-dialog": "^1.0.0-beta.3.0.0",
"aurelia-event-aggregator": "^1.0.1",
"aurelia-fetch-client": "^1.1.2",
"aurelia-framework": "^1.1.0",
"aurelia-history": "^1.0.0",
"aurelia-history-browser": "^1.0.0",
"aurelia-logging": "^1.3.1",
"aurelia-logging-console": "^1.0.0",
"aurelia-metadata": "^1.0.3",
"aurelia-notify": "^0.8.1",
"aurelia-pal": "^1.3.0",
"aurelia-pal-browser": "^1.1.0",
"aurelia-path": "^1.0.0",
"aurelia-route-recognizer": "^1.0.0",
"aurelia-router": "^1.3.0",
"aurelia-task-queue": "^1.2.0",
"aurelia-templating": "^1.3.0",
"aurelia-templating-binding": "^1.3.0",
"aurelia-templating-resources": "^1.3.1",
"aurelia-templating-router": "^1.1.0",
"aurelia-validation": "^1.0.0",
"bluebird": "^3.3.5",
"json-loader": "^0.5.4",
... //omitted for clarity
},
"devDependencies": {
"aurelia-loader-nodejs": "^1.0.1",
"aurelia-pal-nodejs": "^1.0.0-beta.1.0.0",
"aurelia-tools": "^1.0.0",
"aurelia-webpack-plugin": "^2.0.0-rc.2",
"autoprefixer": "^7.0.0",
"babel-core": "^6.17.0",
"babel-eslint": "^7.2.3",
"babel-loader": "^7.0.0",
"babel-plugin-istanbul": "^4.1.3",
"babel-plugin-lodash": "^3.2.10",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-polyfill": "^6.16.0",
"babel-preset-env": "^1.5.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-1": "^6.24.1",
"babel-register": "^6.11.6",
"concurrently": "^2.2.0",
"copy-webpack-plugin": "^4.0.1",
"cross-env": "^3.1.3",
"css-loader": "^0.28.1",
"eslint": "^3.12.2",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.9.0",
"html-server": "^0.1.1",
"html-webpack-plugin": "^2.22.0",
"json-loader": "^0.5.4",
"node-sass": "^3.13.0",
"optimize-css-assets-webpack-plugin": "^1.3.2",
"package": "^1.0.1",
"postcss-loader": "^1.3.3",
"raw-loader": "^0.5.1",
"rimraf": "^2.5.2",
"sass-loader": "^4.0.2",
"style-loader": "^0.17.0",
"url-loader": "^0.5.8",
"webpack": "^2.6.1",
"webpack-dashboard": "^0.2.0",
"webpack-dev-server": "^2.4.5"
}
nav-bar.html
<template>
<require from='./_nav-bar.scss'></require>
<section class="nav-bar nav-bar__group" data-grid="full">
<div data-grid="full">
<main-menu router.bind="router" data-grid="21"></main-menu>
<user-panel data-grid="3"></user-panel>
</div>
</section>
</template>
main-menu.html
<template class="main-menu">
<ul class="main-menu__nav-list">
<li repeat.for="row of router.navigation">
<a href.bind="row.href"
data-appinsights-category="navigation"
data-appinsights-action="${row.title}"
data-text="${row.title}">
${row.title}
</a>
</li>
</ul>
</template>
main-menu.js
import { bindable, inject } from 'aurelia-framework';
#inject(Element)
export class MainMenuCustomElement {
//This value is always undefined now
#bindable router;
constructor(element) {
this.element = element;
}
toggleMenu() {
//removed for brevity
}
}
I got it to work after adding import babel-polyfill to main.js, changing .babelrc to reference `.babelrc.js like so:
{
"presets": [ "./.babelrc.js" ]
}
I also included .babelrc.js from the skeleton-navigation project.
.babelrc.js
// this file will be used by default by babel#7 once it is released
module.exports = {
"plugins": [
"transform-decorators-legacy",
"transform-class-properties"
],
"presets": [
[
"env", {
"targets": process.env.BABEL_TARGET === 'node' ? {
"node": process.env.IN_PROTRACTOR ? '6' : 'current'
} : {
"browsers": [
"last 2 versions",
"not ie <= 11"
],
"uglify": process.env.NODE_ENV === 'production',
},
"loose": true,
"modules": process.env.BABEL_TARGET === 'node' ? 'commonjs' : false,
"useBuiltIns": true
}
]
]
}