Vuejs hot reload Cannot read property 'Ctor' of undefined - vue.js

I have this error when I update:
index.js:106 TypeError: Cannot read property 'Ctor' of undefined
at index.js:202
at Object.reload (index.js:104)
at reload (hot-reload.ts:17)
at router.ts:30
at hotApply (bootstrap 796061b879a4ebee3501:605)
at bootstrap 796061b879a4ebee3501:313
(anonymous) # index.js:106
reload # hot-reload.ts:17
(anonymous) # router.ts:30
hotApply # bootstrap 796061b879a4ebee3501:605
(anonymous) # bootstrap 796061b879a4ebee3501:313
Promise.then (async)
hotUpdateDownloaded # bootstrap 796061b879a4ebee3501:312
hotAddUpdateChunk # bootstrap 796061b879a4ebee3501:289
webpackHotUpdateCallback # bootstrap 796061b879a4ebee3501:31
(anonymous) # 10.796061b879a4ebee3501.hot-update.js:1
I tried to change versions for vue-bootstrap, webpack, hot-reload but I always have this error.
this is my package.json
{
"name": "v5",
"description": "MTN Project V5",
"version": "1.0.0",
"author": "ligadata-alaa <admhemed#gmail.com>",
"private": true,
"engines": {
"node": ">=6",
"npm": ">=3"
},
"scripts": {
"build": "cross-env-shell NODE_ENV=production npm run clean && npm run lint && npm run test && npm run compile",
"ci:teamcity": "karma --env=tc start config/karma.coverage.js && npm run coverage:remap",
"ci:jenkins": "karma --env=jk start config/karma.coverage.js && npm run coverage:remap",
"clean": "rimraf dist && rimraf coverage",
"compile": "webpack --config config/webpack.config.prod.js",
"coverage": "npm run coverage:run && npm run coverage:remap && npm run coverage:open",
"coverage:open": "opn coverage/html-ts/index.html",
"coverage:remap": "remap-istanbul -i coverage/json/coverage-final.json -o coverage/html-ts -t html",
"coverage:run": "cross-env NODE_ENV=development karma start config/karma.coverage.js",
"dev": "webpack-dev-server --config config/webpack.config.dev.js --hot --inline",
"lint": "tslint src/**/*.ts",
"serve": "http-server dist/ -g -o"
},
"dependencies": {
"axios": "~0.17.1",
"bootstrap-vue": "~2.0.0-rc.1",
"vue": "~2.5.13",
"vue-class-component": "~6.1.2",
"vue-property-decorator": "~6.0.0",
"vue-router": "~3.0.1"
},
"devDependencies": {
"#types/mocha": "~2.2.47",
"#types/node": "~9.4.0",
"#types/sinon": "~4.1.3",
"#types/webpack-env": "~1.13.5",
"autoprefixer": "~7.2.5",
"awesome-typescript-loader": "~3.4.1",
"bootstrap": "~4.0.0",
"chai": "~4.1.2",
"compression-webpack-plugin": "~1.1.6",
"copy-webpack-plugin": "~4.3.1",
"cross-env": "~5.1.3",
"css-hot-loader": "~1.3.6",
"css-loader": "~0.28.9",
"cssnano": "~3.10.0",
"es6-promise": "~4.2.4",
"eslint": "^5.4.0",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-promise": "^4.0.0",
"eslint-plugin-standard": "^3.1.0",
"extract-text-webpack-plugin": "~3.0.2",
"favicons-webpack-plugin": "0.0.7",
"file-loader": "~1.1.6",
"html-webpack-plugin": "~2.30.1",
"http-server": "~0.11.1",
"istanbul-instrumenter-loader": "~3.0.0",
"json-loader": "~0.5.7",
"karma": "~2.0.0",
"karma-chai": "~0.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage": "~1.1.1",
"karma-junit-reporter": "~1.2.0",
"karma-mocha": "~1.3.0",
"karma-mocha-reporter": "~2.2.5",
"karma-sinon": "~1.0.5",
"karma-source-map-support": "~1.2.0",
"karma-sourcemap-loader": "~0.3.7",
"karma-teamcity-reporter": "~1.1.0",
"karma-webpack": "~2.0.9",
"lodash.merge": "~4.6.0",
"minimist": "~1.2.0",
"mocha": "~5.0.0",
"ncp": "~2.0.0",
"node-sass": "~4.7.2",
"opn-cli": "~3.1.0",
"optimize-css-assets-webpack-plugin": "~3.2.0",
"postcss-loader": "^2.0.10",
"raw-loader": "~0.5.1",
"remap-istanbul": "~0.10.1",
"rimraf": "~2.6.2",
"sass-loader": "~6.0.6",
"sinon": "~4.2.2",
"standard": "~10.0.3",
"style-loader": "~0.20.1",
"tslint": "~5.9.1",
"tslint-config-standard": "~7.0.0",
"tslint-loader": "~3.5.3",
"typescript": "~2.7.1",
"url-loader": "~0.6.2",
"vue-cli-plugin-vuetify": "^0.1.6",
"vue-hot-reload-api": "~2.2.4",
"webpack": "~3.10.0",
"webpack-dev-server": "~2.11.1"
}
}
main.ts
import Vue from 'vue';
import { makeHot, reload } from './util/hot-reload';
import {router} from './router';
import store from './store/index';
const navbarComponent = () => import('./components/navbar').then(({ NavbarComponent }) => NavbarComponent);
const sidebarComponent = () => import('./components/sidebar').then(({ SidebarComponent }) => SidebarComponent);
const bottombarComponent = () => import('./components/bottombar').then(({ BottombarComponent }) => BottombarComponent);
// const navbarComponent =
// () => import(/* webpackChunkName: 'navbar' */'./components/navbar').then(({ NavbarComponent }) => NavbarComponent)
import './sass/main.scss';
import VueResource from 'vue-resource';
Vue.use(VueResource);
if (process.env.ENV === 'development' && module.hot) {
const navbarModuleId = './components/navbar';
// first arguments for `module.hot.accept` and `require` methods have to be static strings
// see https://github.com/webpack/webpack/issues/5668
makeHot(navbarModuleId, navbarComponent,
module.hot.accept('./components/navbar',
() => reload(navbarModuleId, (require('./components/navbar') as any).NavbarComponent)));
}
// tslint:disable-next-line:no-unused-expression
export const VueApp = new Vue({
el: '#app-main',
router,
store,
http: {
root: ''
},
components: {
navbar: navbarComponent,
sidebar: sidebarComponent,
bottombar: bottombarComponent
}
});
Vue.config.productionTip = false;
router.ts
import Vue from 'vue';
import VueRouter, { Location, Route, RouteConfig } from 'vue-router';
import { makeHot, reload } from './util/hot-reload';
import store from './store/index';
const homeComponent = () => import('./components/home').then(({ HomeComponent }) => HomeComponent);
const aboutComponent = () => import('./components/about').then(({ AboutComponent }) => AboutComponent);
const htmlComponent = () => import('./components/html').then(({ HtmlComponent }) => HtmlComponent);
const gridComponent = () => import('./components/grid').then(({ GridComponent }) => GridComponent);
// const homeComponent = () =>
// import(/* webpackChunkName: 'home' */'./components/home').then(({ HomeComponent }) => HomeComponent)
// const aboutComponent = () =>
// import(/* webpackChunkName: 'about' */'./components/about').then(({ AboutComponent }) => AboutComponent)
// const listComponent = () =>
// import(/* webpackChunkName: 'list' */'./components/list').then(({ ListComponent }) => ListComponent)
if (process.env.ENV === 'development' && module.hot) {
const homeModuleId = './components/home';
const htmlModuleId = './components/html';
const gridModuleId = './components/grid';
const aboutModuleId = './components/about';
// first arguments for `module.hot.accept` and `require` methods have to be static strings
// see https://github.com/webpack/webpack/issues/5668
makeHot(homeModuleId, homeComponent,
module.hot.accept('./components/home',
() => reload(homeModuleId, (require('./components/home') as any).HomeComponent)));
makeHot(homeModuleId, gridComponent,
module.hot.accept('./components/grid',
() => reload(gridModuleId, (require('./components/grid') as any).GridComponent)));
makeHot(aboutModuleId, htmlComponent,
module.hot.accept('./components/about',
() => reload(aboutModuleId, (require('./components/about') as any).AboutComponent)));
makeHot(aboutModuleId, aboutComponent,
module.hot.accept('./components/about',
() => reload(aboutModuleId, (require('./components/about') as any).AboutComponent)));
}
Vue.use(VueRouter);
export const createRoutes: () => RouteConfig[] = () => [
{
path: '/',
component: homeComponent
},
{
path: '/home',
component: homeComponent
},
{
path: '/grid',
component: gridComponent
},
{
path: '/html',
component: htmlComponent
},
{
path: '/about',
component: aboutComponent
}
];
export const createRouter = () => new VueRouter({ mode: 'history', routes: createRoutes() });
export const router = createRouter();
router.afterEach((to, from) => {
if (to.path === '/grid') {
store.dispatch('search/checkIfThereIsASearch', []);
}
});

I got over it just by refreshing the page.

If you have changed the versions
try clearing node modules
reinstall/update npm modules
this will ensure all modules are new and correctly installed

Please upgrade vue-loader to 15.7.1. This PR should fix it.

Related

Component is missing template or render function - VueJS Library

I am trying to create an SVG library using Vue3 but all I am getting is error...I created the basic library project following this article. Here is my file structure
and this is my code in BaseIcon.vue
<template>
<component :is="iconComponent" class="inline-block fill-current"
style="height: 1em; width: 1em; vertical-align: -0.125em" />
</template>
<script>
const icons = {}
const requireComponents = require.context('../assets/icons/', false, /.svg$/)
requireComponents.keys().forEach(fileName => {
const iconName = fileName.replace(/^\.\/icon-(.+)\.svg$/, '$1')
const componentConfig = requireComponents(fileName)
icons[iconName] = componentConfig.default || componentConfig
})
export default {
props: {
name: {
type: String,
required: true,
validator(value) {
return Object.prototype.hasOwnProperty.call(icons, value)
}
}
},
computed: {
iconComponent() {
return icons[this.name]
},
}
}
</script>
This is the App.vue file code
<template>
<div id="app" class="p-10 text-xl">
<BaseIcon name="user" class="text-blue-500" /> Home
<BaseIcon name="home" class="text-blue-500" /> Profile
</div>
</template>
<script>
import BaseIcon from './BaseIcon.vue'
export default {
name: 'App',
components: {
BaseIcon,
}
}
</script>
My Index.js looks like this
/* eslint-disable import/prefer-default-export */
export { default as App } from './App.vue'
Dev Dependencies in my Package.json are these:
"devDependencies": {
"#babel/core": "^7.14.6",
"#babel/preset-env": "^7.14.7",
"#rollup/plugin-alias": "^3.1.2",
"#rollup/plugin-babel": "^5.3.0",
"#rollup/plugin-commonjs": "^14.0.0",
"#rollup/plugin-node-resolve": "^9.0.0",
"#rollup/plugin-replace": "^2.4.2",
"#vue/cli-plugin-babel": "^4.5.13",
"#vue/cli-service": "^4.5.13",
"#vue/compiler-sfc": "^3.1.0-0",
"cross-env": "^7.0.3",
"minimist": "^1.2.5",
"postcss": "^8.2.10",
"rimraf": "^3.0.2",
"rollup": "^2.52.8",
"rollup-plugin-postcss": "^4.0.0",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-vue": "^6.0.0",
"vue-loader": "16.8.3",
"vue-svg-loader": "^0.17.0-beta.2",
"vue": "^3.0.5"
},
and I've added vue.config.json with following settings:
module.exports = {
chainWebpack: (config) => {
const svgRule = config.module.rule('svg');
svgRule.uses.clear();
svgRule
.use('babel-loader')
.loader('babel-loader')
.end()
.use('vue-svg-loader')
.loader('vue-svg-loader');
},
};
And here is what I am getting as error:
I'm not sure what I am missing here, or what is wrong.. Any kind of help will be appreciated, because its been days that I am stuck here and just couldn't get any idea of resolving this.

Inertia.js ssr: ReferenceError: document is not defined

I am using Laravel 8 with Inertia.js version 0.5.4. Can anyone help solve this problem? The app works fine without the ssr. I think the problem is in the Webpack config file.
ReferenceError: document is not defined
package.json
"#inertiajs/inertia": "^0.11.0",
"#inertiajs/inertia-vue": "^0.8.0",
"laravel-mix": "^6.0",
"sass": "~1.32",
"sass-loader": "^12.2.0",
"vue-cli-plugin-vuetify": "~2.3.1",
"vue-loader": "^15.9.6",
"vue-template-compiler": "^2.6.10",
"vuetify-loader": "^1.7.0",
"webpack": "^5.59.1",
"vue": "^2.6.14",
"vue-server-renderer": "^2.6.14",
"vuetify": "^2.5.5",
"vuetifyjs-mix-extension": "0.0.20",
"vuex": "^3.4.0",
"webpack-node-externals": "^3.0.0"
webpack.ssr.mix.js
const path = require('path')
const mix = require('laravel-mix')
const webpackNodeExternals = require('webpack-node-externals');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
mix
.options({ manifest: false, processCssUrls: false })
.js('resources/js/ssr.js', 'public/js')
.vue({
version: 2, options: { optimizeSSR: true }
})
.webpackConfig({
resolve: {
alias: {
'#resources': path.resolve('resources'),
'{Template}': path.resolve('resources/js/Themes/default'),
'#themeConfig': path.resolve('themeConfig.js'),
'#core': path.resolve('resources/#core'),
'#axios': path.resolve('resources/js/plugins/axios.js'),
'#user-variables': path.resolve('resources/sass/variables.scss'),
'#sass': path.resolve('resources/sass/'),
'apexcharts': path.resolve(__dirname, 'node_modules/apexcharts-clevision'),
'#': path.resolve('resources/js'),
},
},
plugins: [new MiniCssExtractPlugin(
{
filename: "[name].css",
chunkFilename: "[id].css",
linkType: false,
}
)],
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
// enable CSS extraction
extractCSS: true
}
}
// ...
]
},
target: 'node',
devtool: 'source-map',
externals: [webpackNodeExternals({
// this WILL include `jquery` and `webpack/hot/dev-server` in the bundle, as well as `lodash/*`
allowlist: [/^vuetify/, /^lodash/, 'vue-tel-input-vuetify/lib', /^vue-tel-input-vuetify^/, /^apexcharts^/, /^vue-apexcharts/, /apexcharts/, /apexcharts-clevision/, /^apexcharts-clevision/, /^apexcharts-clevision^/, /^vue-country-flag/, /\.css$/]
})],
})
ssr.js
import Vue from 'vue'
import {createRenderer} from 'vue-server-renderer'
import {createInertiaApp} from '#inertiajs/inertia-vue'
import createServer from '#inertiajs/server'
import PortalVue from 'portal-vue';
import store from './store'
import './plugins/acl'
import VueCompositionAPI from '#vue/composition-api'
import VueMeta from 'vue-meta'
import vuetify from '#/plugins/vuetify'
import Layout from '#/Layouts/AdminLayout.vue'
import AppLayout from "#/Layouts/AppLayout.vue"
import UserLayout from "#/Layouts/UserLayout.vue"
import ClientOnly from 'vue-client-only'
const moment = require('moment');
createServer((page) => createInertiaApp({
page,
render: createRenderer().renderToString,
// resolve: name => require(`./Pages/${name}`),
resolve: (name) => {
// const page = (await import(`./Pages/${name}`)).default
const page = require(`./Pages/${name}`);
if (page.layout === undefined && name.startsWith('Admin/')) {
page.layout = Layout
}
if (page.layout === undefined && name.startsWith('Dashboard/')) {
page.layout = Layout
}
if (page.layout === undefined && name.startsWith('UserDashboard/')) {
page.layout = UserLayout
}
if (page.layout === undefined && !name.startsWith('Admin/') && !name.startsWith('Dashboard/')) {
page.layout = AppLayout
}
return page
},
setup({app, props, plugin}) {
Vue.use(plugin);
Vue.use(VueCompositionAPI);
Vue.use(PortalVue);
Vue.component('client-only', ClientOnly)
Vue.use(VueMeta, {
// optional pluginOptions
refreshOnceOnNavigation: true
})
Vue.mixin({methods: {route}});
return new Vue({
vuetify: vuetify,
store,
render: h => h(app, props),
})
},
}))
npx mix --mix-config=webpack.ssr.mix.js
result : webpack compiled successfully
node public/js/ssr.js
error :
var style = document.createElement('style');
^
ReferenceError: document is not defined
at insertStyleElement (C:\laragon\www\test2\public\js\ssr.js:44989:15)
at addStyle (C:\laragon\www\test2\public\js\ssr.js:45104:13)
at modulesToDom (C:\laragon\www\test2\public\js\ssr.js:44977:18)
at module.exports (C:\laragon\www\test2\public\js\ssr.js:45135:25)
at Module../resources/sass/overrides.scss (C:\laragon\www\gooreo2\public\js\ssr.js:41942:145)
at webpack_require (C:\laragon\www\test2\public\js\ssr.js:130966:42)
at Module../resources/js/plugins/vuetify/default-preset/preset/index.js
(C:\laragon\www\test2\public\js\ssr.js:38073:1)
at webpack_require (C:\laragon\www\test2\public\js\ssr.js:130966:42)
at Module../resources/js/plugins/vuetify/index.js (C:\laragon\www\test2\public\js\ssr.js:38099:80)
at webpack_require
(C:\laragon\www\test2\public\js\ssr.js:130966:42)
public/js/ssr.js
You can fix it is by adding one line to your webpack.mix.js to opt in to using the vue-style-loader
mix
.js('resources/js/ssr.js', 'public/js')
.vue({
version: 3,
useVueStyleLoader: true // This should fix it!
});
Ref: https://aaronfrancis.com/2021/vue-referenceerror-document-is-not-defined-at-insertstyleelement

Can't upload files with Apollo-client GraphQL in Next.js app: POST body missing

I am trying to implement avatar upload in Next.js blog with Node.js server using Apollo client + apollo-upload-client on client side and apollo-express-server on server side.
I've got the next error:
POST body missing. Did you forget use body-parser middleware?
I am sure that I have body parser on my server.
Server.ts
import "reflect-metadata";
import "dotenv-safe/config";
import 'module-alias/register';
import { __prod__ } from "#/config/config";
import express from "express";
import Redis from "ioredis";
import session from "express-session";
import connectRedis from "connect-redis";
import { createConnection } from "typeorm";
import { User } from "#/entities/User";
import { Project } from "#/entities/Project";
import path from "path";
const server = async () => {
await createConnection({
type: "postgres",
url: process.env.DATABASE_URL,
logging: true,
migrations: [path.join(__dirname, "./migrations/*")],
entities: [User, Project]
});
const app = express();
require("#/start/logger"); // log exceptions
const RedisStore = connectRedis(session); // connect redis store
const redis = new Redis(process.env.REDIS_URL);
require("#/start/apolloServer")(app, redis); // create apollo server
require("#/start/appConfig")(app,redis,RedisStore) // configure app
const PORT = process.env.PORT || 3007;
app.listen(PORT, () => {
console.log(`🚀 Server Started at PORT: ${PORT}`);
});
};
server().catch((err) => {
console.error(err);
});
My Apollo Server
I use apollo-server-express
import { ApolloServer, gql } from "apollo-server-express";
import { buildSchema } from "type-graphql";
import ProfilePictureResolver from "#/resolvers/upload";
import { createUserLoader } from "#/utils/createUserLoader";
import { UserResolver } from "#/resolvers/user";
import { ProjectResolver } from "#/resolvers/project";
import {Express} from "express";
import { Redis } from "ioredis";
const typeDefs = gql`
scalar Upload
type File {
id: ID!
filename: String!
mimetype: String!
path: String!
}
type Mutation {
singleUpload(file: Upload!): File!
}
`;
module.exports = async function(app:Express,redis:Redis){
const apolloServer = new ApolloServer({
typeDefs,
schema: await buildSchema({
resolvers: [UserResolver, ProjectResolver, ProfilePictureResolver],
validate: false,
}),
context: ({ req, res }) => ({
req,
res,
redis,
userLoader: createUserLoader()
}),
uploads: false
});
apolloServer.applyMiddleware({
app,
cors: false,
});
}
Resolver:
import { Resolver, Mutation, Arg } from 'type-graphql'
import { GraphQLUpload, FileUpload } from 'graphql-upload'
import os from 'os'
import { createWriteStream } from 'fs'
import path from 'path'
#Resolver()
export default class SharedResolver {
#Mutation(() => Boolean)
async uploadImage(
#Arg('file', () => GraphQLUpload)
file: FileUpload
): Promise<Boolean> {
const { createReadStream, filename } = await file
const destinationPath = path.join(os.tmpdir(), filename)
const url = await new Promise((res, rej) =>
createReadStream()
.pipe(createWriteStream(destinationPath))
.on('error', rej)
.on('finish', () => {
//stuff to do
})
);
return true;
}
}
Server config
import {Express} from 'express'
import { __prod__, COOKIE_NAME } from "#/config/config";
import cors from "cors";
import session from "express-session";
import { Redis } from 'ioredis';
import { RedisStore } from 'connect-redis';
import { bodyParserGraphQL } from 'body-parser-graphql'
module.exports = function(app:Express, redis:Redis, RedisStore:RedisStore){
app.set("trust proxy", 1);
app.use(bodyParserGraphQL());
app.use(
cors({
origin: process.env.CORS_ORIGIN,
credentials: true,
})
);
app.use(
session({
name: COOKIE_NAME,
store: new RedisStore({
client: redis,
disableTouch: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10, // 10 years
httpOnly: true,
sameSite: "lax",
secure: __prod__,
domain: __prod__ ? ".heroku.com" : undefined,
},
saveUninitialized: false,
secret: process.env.SESSION_SECRET,
resave: false,
})
);
}
Client
App client
import { createWithApollo } from "#/utils/createWithApollo";
import { ApolloClient, InMemoryCache } from "#apollo/client";
import { NextPageContext } from "next";
import { createUploadLink } from 'apollo-upload-client';
const createClient = (ctx: NextPageContext) =>
new ApolloClient({
credentials: "include",
headers: {
cookie:
(typeof window === "undefined"
? ctx?.req?.headers.cookie
: undefined) || "",
},
cache: new InMemoryCache({
typePolicies: {
Query: {}
}
}),
link: createUploadLink({uri:'http://localhost:4000/graphql'})
});
// const createClient: ApolloClient<NormalizedCacheObject> = new ApolloClient({
// cache: new InMemoryCache({}),
// uri: 'http://localhost:4000/graphql'
// });
export const withApollo = createWithApollo(createClient);
Query
import { gql } from '#apollo/client';
export const UPLOAD_IMAGE_MUTATION = gql`
mutation uploadImage($file: Upload!) {
uploadImage(file: $file)
}
`;
Page
import React, {useState} from 'react';
import {useSelector} from "react-redux";
import {Box} from "#/components/UI/Box/Box"
import {Header} from "#/components/UI/Text/Header"
import { withApollo } from "#/utils/withApollo";
import withPrivateRoute from "#/HOC/withPrivateRoute";
import { useMutation } from "#apollo/react-hooks";
import { UPLOAD_IMAGE_MUTATION } from "#/graphql/mutations/uploadImage";
interface IProps{};
const Profile:React.FC<IProps> = () => {
const user = useSelector(state => state.user);
const [file, setFileToUpload] = useState(null);
const [uploadImage, {loading}] = useMutation(UPLOAD_IMAGE_MUTATION);
const onAvatarUpload = (e) =>{
setFileToUpload(e.target.files[0]);
}
const onSubmit = async (e) =>{
e.preventDefault();
const response = await uploadImage({
variables: {file}
});
}
return (
<Box mt={20} pl={30} pr={30}>
<Header>
Edit Profile
</Header>
<input onChange={onAvatarUpload} type="file" placeholder="photo" />
<button onClick={(e)=>onSubmit(e)}>Submit</button>
</Box>
)
};
export default withApollo({ ssr: false })(withPrivateRoute(Profile, true));
My Client package:
{
"name": "app",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"#apollo/client": "^3.2.5",
"#apollo/react-hooks": "^4.0.0",
"apollo-upload-client": "^14.1.3",
"graphql": "^15.4.0",
"graphql-tag": "^2.11.0",
"graphql-upload": "^11.0.0",
"isomorphic-unfetch": "^3.1.0",
"next": "^9.5.5",
"next-apollo": "^5.0.3",
"next-redux-wrapper": "^6.0.2",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-is": "^16.13.1",
"react-redux": "^7.2.2",
"redux": "^4.0.5",
"styled-components": "^5.2.1",
"urql": "^1.10.3",
"uuid": "^8.3.1"
},
"devDependencies": {
"#testing-library/jest-dom": "^5.11.5",
"#testing-library/react": "^11.1.1",
"#types/graphql": "^14.5.0",
"#types/jest": "^26.0.15",
"#types/next": "^9.0.0",
"#types/node": "^14.0.27",
"#types/react": "^16.9.55",
"#types/react-dom": "^16.9.9",
"#types/styled-components": "^5.1.4",
"#types/uniqid": "^5.2.0",
"#types/uuid": "^8.3.0",
"#welldone-software/why-did-you-render": "^5.0.0",
"babel-plugin-inline-react-svg": "^1.1.2",
"babel-plugin-module-resolver": "^4.0.0",
"babel-plugin-styled-components": "^1.11.1",
"redux-devtools-extension": "^2.13.8",
"typescript": "^4.0.5"
}
}
Server package:
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "server.ts",
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"nodemon": "nodemon dist/server.js",
"dev": "npm-run-all --parallel watch nodemon",
"start": "ts-node src/server.ts",
"client": "cd ../ && npm run dev --prefix client",
"runall": "npm-run-all --parallel client dev",
"typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js",
"migration:up": "typeorm migration:run",
"migration:down": "typeorm migration:revert",
"migration:generate": "typeorm migration:generate -n 'orm_migrations'"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"apollo-server-express": "^2.16.1",
"argon2": "^0.26.2",
"connect-redis": "^5.0.0",
"cors": "^2.8.5",
"dataloader": "^2.0.0",
"dotenv-safe": "^8.2.0",
"express": "^4.17.1",
"express-async-errors": "^3.1.1",
"express-session": "^1.17.1",
"graphql": "^15.3.0",
"ioredis": "^4.17.3",
"module-alias": "^2.2.2",
"path": "^0.12.7",
"pgtools": "^0.3.0",
"reflect-metadata": "^0.1.13",
"type-graphql": "^1.0.0-rc.3",
"typeorm": "^0.2.25",
"uuid": "^8.3.0",
"winston": "^3.3.3"
},
"devDependencies": {
"#types/connect-redis": "0.0.14",
"#types/cors": "^2.8.8",
"#types/express": "^4.17.8",
"#types/express-session": "^1.17.0",
"#types/graphql": "^14.5.0",
"#types/ioredis": "^4.17.7",
"#types/node": "^8.10.66",
"#types/nodemailer": "^6.4.0",
"#types/pg": "^7.14.6",
"#types/uuid": "^8.3.0",
"gen-env-types": "^1.0.4",
"nodemon": "^2.0.6",
"npm-run-all": "^4.1.5",
"pg": "^8.4.2",
"ts-node": "^8.10.2",
"typescript": "^3.9.7"
},
"_moduleAliases": {
"#": "dist/"
}
}
NOTE!
When I try to remove uploads: false from apolloServer configuration I receive another error:
"Variable "$file" got invalid value {}; Upload value invalid."
And indeed in form data I see
------WebKitFormBoundarybNufV7QLX3EU1SN6 Content-Disposition: form-data; name="operations"
{"operationName":"uploadImage","variables":{"file":null},"query":"mutation
uploadImage($file: Upload!) {\n uploadImage(file: $file)\n}\n"}
------WebKitFormBoundarybNufV7QLX3EU1SN6 Content-Disposition: form-data; name="map"
{"1":["variables.file"]}
------WebKitFormBoundarybNufV7QLX3EU1SN6 Content-Disposition: form-data; name="1"; filename="Screen Shot 2020-11-20 at 17.56.14.png"
Content-Type: image/png
------WebKitFormBoundarybNufV7QLX3EU1SN6--
I am 100% sure that I pass the file.
I faced the same problem in my NextJs project, I found that the resolver of Upload checks if the value is instanceOf Upload, and that is somehow not working.
I fix it by creating my own resolver without using the 'graphql-upload' package like this:
Solution 1 :
export const resolvers: Resolvers = {
Upload: new GraphQLScalarType({
name: 'Upload',
description: 'The `Upload` scalar type represents a file upload.',
parseValue(value) {
return value;
},
parseLiteral(ast) {
throw new GraphQLError('Upload literal unsupported.', ast);
},
serialize() {
throw new GraphQLError('Upload serialization unsupported.');
},
})
};
Solution 2 :
Or you can just don't declare any resolver for this type.
Note:
Be sure that you declared scalar type of Upload in your schema and you need to add the uploads field to your Apollo Server configuration:
const apolloServer = new ApolloServer({
uploads: {
maxFileSize: 10000000, // 10 MB
maxFiles: 20
},
.
.
.

webpack 4 aspnetcore 2.2 HMR not reloading in browser

I'm unable to rule out a compatibility issue with aspnetcore 2.2 and webpack 4 or a configuration issue on my end.
I need some help spotting the configuration issue if that is the cause.
ASPNETCORE 2.2
WEBPACK 4
When I make a change to a ".tsx" file, Visual Studio outputs that webpack has rebuilt, however the browser is not refreshing and there are no messages in the console. (I do however get the initial HMR connected message in the browser console).
Visual Studio output:
Microsoft.AspNetCore.NodeServices:Information: webpack building...
Microsoft.AspNetCore.NodeServices:Information: Checking
started in a separate process...
754ms Microsoft.AspNetCore.NodeServices:Information: webpack built
1e45bf5f88ad514f4a12 in 4940ms
Compiled successfully.
starting HTTP/1.1 GET https://localhost:44331/__webpack_hmr
webpack.config.js:
const path = require('path');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
module.exports = (env) => {
const isDevBuild = !(env && env.prod);
const outputDir = (env && env.publishDir)
? env.publishDir
: __dirname;
return [{
mode: isDevBuild ? 'development' : 'production',
devtool: 'inline-source-map',
stats: { modules: false },
entry: { 'main': './client/boot.tsx' },
watchOptions: {
ignored: /node_modules/
},
output: {
filename: "dist/[name].js",
path: path.join(outputDir, 'wwwroot'),
publicPath: '/'
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".json"]
},
devServer: {
hot: true
},
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{
test: /\.tsx?$/,
include: /client/,
loader: [
{
loader: 'awesome-typescript-loader',
options: {
useCache: true,
useBabel: true,
babelOptions: {
babelrc: false,
plugins: ['react-hot-loader/babel'],
}
}
}
]
},
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [
new CleanWebpackPlugin(path.join(outputDir, 'wwwroot', 'dist')),
new CheckerPlugin()
]
}];
};
Startup.cs Configure:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true
});
}
package.json:
"devDependencies": {
"#babel/core": "*",
"#babel/preset-env": "*",
"#types/history": "4.6.0",
"#types/jest": "^23.3.2",
"#types/node": "^10.9.1",
"#types/react": "^16.7.13",
"#types/react-dom": "16.0.11",
"#types/react-hot-loader": "3.0.3",
"#types/react-router": "4.4.1",
"#types/react-router-dom": "4.3.1",
"#types/webpack-env": "^1.13.6",
"aspnet-webpack": "^3.0.0",
"awesome-typescript-loader": "^5.2.0",
"babel-core": "7.0.0-bridge.0",
"babel-jest": "*",
"clean-webpack-plugin": "^0.1.19",
"crypto-js": "^3.1.9-1",
"css-loader": "0.28.4",
"enzyme-to-json": "^3.3.4",
"event-source-polyfill": "0.0.9",
"extract-text-webpack-plugin": "2.1.2",
"file-loader": "0.11.2",
"file-saver": "^1.3.8",
"isomorphic-fetch": "2.2.1",
"jest": "^23.6.0",
"jquery": "^3.2.1",
"json-loader": "0.5.4",
"moment": "^2.22.2",
"raf": "^3.4.0",
"react": "^16.6.3",
"react-deep-force-update": "2.1.1",
"react-dom": "^16.6.3",
"react-hot-loader": "^4.0.0",
"react-router-dom": "4.1.1",
"react-select": "^2.0.0",
"style-loader": "0.18.2",
"ts-jest": "^23.10.3",
"ts-loader": "^2.0.1",
"typescript": "^2.9.2",
"url-loader": "0.5.9",
"webpack": "^4.15.1",
"webpack-cli": "^3.0.8",
"webpack-dev-middleware": "^3.1.3",
"webpack-hot-middleware": "^2.22.2"
EDIT: (adding boot.tsx and app.tsx to show hot module loading)
boot.tsx
import * as React from 'react';
import { runWithAdal } from 'react-adal';
import * as ReactDOM from 'react-dom';
import App from './app';
import { authContext } from './authentication/azure/azureConfig';
const DO_NOT_LOGIN = false;
function renderApp() {
ReactDOM.render(
<App />,
document.getElementById('react-app')
);
}
runWithAdal(authContext, () => {
renderApp();
}, DO_NOT_LOGIN);
app.tsx
import * as React from 'react';
import { hot } from 'react-hot-loader';
import { Provider } from 'react-redux';
import * as RoutesModule from './routes';
import { BrowserRouter } from 'react-router-dom';
import configureStore from './store/configureStore';
let routes = RoutesModule.routes;
const store = configureStore({});
const baseUrl =
document.getElementsByTagName('base')[0].getAttribute('href')!;
const App: React.SFC = () => <Provider store={store}>
;
export default hot(module)(App);
According to your above configuration, you're packing the js files into "wwwroot/dist/[name].js". The output information indicates that the Webpack hot reload feature is set up correctly. But it seems that Webpack has no idea on what the index page is. In other words, any changes made to *.tsx modules will only reload the compiled wwwroot/dist/main.js file.
For example, I create an App.tsx file:
import * as React from "react";
import * as ReactDOM from 'react-dom';
export const App = () => <div>Hello World!</div>
and render the App.tsx in the boot.tsx.
import * as React from "react";
import * as ReactDOM from 'react-dom';
import {App} from "./App";
ReactDOM.render(<App/>, document.getElementById("appconainer"));
When I serve the index page by MVC or StaticFiles, and then test with your configuration, Webpack won't know it should make a request to home/index action (or some "index.htm" url) to refresh.
A possible approach to fix
Since you've installed the react-hot-loader package, one approach is to use a hot() function to convert the root component to be hot-exported:
// file: `App.tsx`
import { hot } from 'react-hot-loader/root'
export const App = () => <div>Hello World!</div>
export const HotApp = hot(App); // make it hot-exported!
and render the hot-exported root component:
// file: root.tsx
import * as React from "react";
import * as ReactDOM from 'react-dom';
import {HotApp} from "./App"; // use the Hot-Exported component as the root component
ReactDOM.render(<App/>, document.getElementById("appconainer"));
For more details, see docs here

[Vue warn]: Unknown custom element: <nuxt-link> - When running jest unit tests

Problem
I'm using nuxt 1.4 with routing using Jest to do unit testing. My application doesn't throw errors and seems to work perfectly. However when running my unit test npm run unit (which runs jest) it throws an error in the terminal: [Vue warn]: Unknown custom element: <nuxt-link> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
Expected
I would expect it to not throw this error since my application is working.
Files
package.json:
{
"name": "vue-starter",
"version": "1.0.0",
"description": "Nuxt.js project",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
"precommit": "npm run lint",
"test": "npm run lint && npm run unit",
"unit": "jest",
"unit:report": "jest --coverage"
},
"dependencies": {
"babel-jest": "^22.4.1",
"jest-serializer-vue": "^1.0.0",
"node-sass": "^4.7.2",
"npm": "^5.7.1",
"nuxt": "^1.0.0",
"sass-loader": "^6.0.7",
"vue-jest": "^2.1.1"
},
"devDependencies": {
"#vue/test-utils": "^1.0.0-beta.12",
"babel-eslint": "^8.2.1",
"eslint": "^4.15.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-loader": "^1.7.1",
"eslint-plugin-vue": "^4.0.0",
"jest": "^22.4.2"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"jest": {
"moduleFileExtensions": [
"js",
"vue"
],
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/babel-jest",
".*\\.(vue)$": "<rootDir>/node_modules/vue-jest"
},
"snapshotSerializers": [
"<rootDir>/node_modules/jest-serializer-vue"
]
}
}
The component that I test:
<template>
<div>
<nuxt-link class="name" :to="{ path: `entity/${item.id}`, params: { id: item.id }}">{{item.name}}</nuxt-link>
<button class="connect" #click="connect">{{ btnText }}</button>
</div>
</template>
<script>
// import nuxtLink from '../.nuxt/components/nuxt-link';
const connectionStatusMap = [
'Connect',
'Connected',
'Pending',
'Cancel',
];
export default {
/*components: {
'nuxt-link': nuxtLink,
},*/
props: {
item: {
type: Object
}
},
...
}
</script>
My test script:
import TestItem from '../components/TestItem';
import { shallow, mount, createLocalVue } from '#vue/test-utils';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(VueRouter)
...
it(`should show the entity`, () => {
const wrapper = mount(TestItem, {
propsData: { item },
localVue,
store,
// stubs: ['nuxt-link'],
})
expect(wrapper.find('.name').text()).toBe(item.name);
});
it(`should show allow me to connect if I'm not yet connected`, () => {
const wrapper = shallow(TestItem, {
propsData: { item },
localVue,
store,
stubs: ['nuxt-link'],
})
expect(wrapper.find('.connect').text()).toBe('Connect');
});
...
I tried
I tried creating a localVue and also stubbing the component as suggested in this github comment
I also tried shallow/mount but that did not seem to work either.
This is how I was able to get rid of the annoying warning:
Include RouterLinkStub, eg.:
import { shallowMount, createLocalVue, RouterLinkStub } from '#vue/test-utils';
Map NuxtLink stub to RouterLinkStub
const wrapper = shallowMount(TestItem, {
...
stubs: {
NuxtLink: RouterLinkStub
}
})
And in case you were checking nuxt-link text or something, change:
const link = wrapper.find('nuxt-link');
to
const link = wrapper.find(RouterLinkStub);
Found this gold on https://onigra.github.io/blog/2018/03/19/vue-test-utils-router-link-stub/
Good thing you don't need to know japanese to read code...
Although the answers provided could work. What I ended up using was based on this guide
const wrapper = mount(TestItem, {
propsData: { item },
localVue,
store,
stubs: {
NuxtLink: true,
// Any other component that you want stubbed
},
});
I managed to get it working using this workaround for Storybook:
import { mount, createLocalVue } from '#vue/test-utils'
import Component from '#/components/Component.vue'
const localVue = createLocalVue()
localVue.component('nuxt-link', {
props: ['to'],
template: '<slot>NuxtLink</slot>',
})
describe('Test Component', () => {
const wrapper = mount(Component, {
stubs: ['nuxt-link'],
localVue
})
})
I added below lines of code to get this working.
In your test file
import NuxtLink from "path to nuxt-link.js"
Mycomponent.components.NuxtLink = NuxtLink
In your jest conf file
transformIgnorePatterns: [
"path to nuxt-link.js"
],
Or you could add below line in mount options
mount(Mycomponent, {stubs: ["nuxt-link"]})
I have:
// path: ./test/jest.setup.js
import Vue from 'vue'
import VueTestUtils from '#vue/test-utils'
// Mock Nuxt components
VueTestUtils.config.stubs['nuxt-link'] = '<a><slot /></a>'
VueTestUtils.config.stubs['no-ssr'] = '<span><slot /></span>'
and
// path: ./jest.config.js
module.exports = {
// ... other stuff
setupFilesAfterEnv: ['./test/jest.setup.js']
}
... and this solves all my jest test in the nuxt app
To anyone getting the Unknow custom element: <router-link>
My issue was, I used mount instead of shallow when creating the component.
shallow usage:
Like mount, it creates a Wrapper that contains the mounted and
rendered Vue component, but with stubbed child components.
Source: https://vue-test-utils.vuejs.org/en/api/shallow.html
Here is a working example
import { shallow } from '#vue/test-utils';
import ContentCard from '../../components/ContentCard.vue';
import NuxtLink from '../../.nuxt/components/nuxt-link';
const createComponent = propsData => shallow(ContentCard, { propsData });
describe('ContentCard', () => {
let component;
beforeEach(() => {
ContentCard.components = ContentCard.components || {};
ContentCard.components.NuxtLink = NuxtLink;
});
describe('Properties', () => {
it('has an imgSrc property', () => {
component = createComponent({ imgSrc: 'X' });
expect(component.props().imgSrc).toBe('X');
});
});
});
...
import NuxtLink from '../.nuxt/components/nuxt-link.js'
...
TestItem.components = TestItem.components || {};
TestItem.components.NuxtLink = NuxtLink;
const wrapper = shallow(TestItem, {
...
});
...
// test/jestSetup.js
import Vue from 'vue'
import Vuetify from 'vuetify'
import { config } from '#vue/test-utils'
Vue.use(Vuetify)
config.stubs.NuxtLink = { template: '<a><slot /></a>' }