I am migrating and app with pretty old react-router (2.8.0) to v6. I couldn't find out how to migrate this line.
const ReactRouter = require( 'react-router' ),
createHashHistory = require( 'react-outer/node_modules/history/lib/createHashHistory' ),
createHashHistory = require( 'react-router/node_modules/history' ).createHashHistory,
useRouterHistory = ReactRouter.useRouterHistory;
var appHistory = useRouterHistory(createHashHistory)( { queryKey: false } );
I found out that the location for createHashHistory changed to require( 'react-router/node_modules/history' ).createHashHistory, but I couldn't find out what to do with useRouterHistory.
If I omit it I no longer have query in the object causing a lot of dependent code to break.
I read through this issue, but all the links there are broken:(
Any ideas?
Related
I'm working in MySQL Database class. In React Project, I can instantiate a File([Blob],filename). But in the Express Backend project, I can't use File module. It show an error as ReferenceError: File is not defined. I don't know how to use them without importing like the React project.
Here is my code for instantiating the File() Object. I tried to import it from "buffer"
downloadProfile = (id,success) => {
this.db.query(`SELECT pi.Filename, pi.Data AS Buffer, pi.MIME, pd.Data FROM profile_image AS pi JOIN profile_data AS pd ON pi.UserID = pd.UserID WHERE pi.UserID = ? AND pd.UserID = ?`,
[id,id],(err,result)=>{
if (err) throw err
const filename = result[0]["Filename"]
const buffer = result[0]["Buffer"]
const mime = result[0]["MIME"]
const image = this.getImageBase64(buffer,mime)
const imageBlob = new Blob([buffer],{type:mime})
const iamgeFile = new File([imageBlob],filename,{type:mime})
const data = JSON.parse(result[0]["Data"])
success({["Data"]:data,["Image"]:image})
})
}
In addition, which one between CommonJS and Module that recommend to working with Node.js Express project.
I have created a very complex build process for front-end of one web app, which is being tested on Appveyor. If some parts of the app are not being built correctly with gulp, if some gulp tasks fail, how do I signal the Appveyor that the build has failed in its entirety?
To solve this problem, I have used instructions from this article. I had a need to separate build process into two similar parts: one for development environment and another one for production environment. Main difference was that production environment should always break if error is found in some of the tasks. Feodor Fitsner suggested that process should exit with non-zero error code.
Combining these two solutions, I created this small JS module that should be used as a wrapper for gulp tasks:
const msg = require('bit-message-box')
const chalk = require('chalk')
module.exports = (taskFn, production = false) => function(done) {
let onSuccess = () => {
done()
}
let onError = (err) => {
if (production) {
// If build process is initiated in production env, it should always break
// on error with exit code higher than zero. This is especially important
// for Appveyor CI
msg.error(`ERROR! BUILD PROCESS ABORTED!`)
console.error(chalk.bgRed.white(err))
process.exit(1)
}
else { done() }
}
let outStream = taskFn(onSuccess, onError);
if (outStream && typeof outStream.on === 'function') {
outStream.on('end', onSuccess);
}
}
Then in gulp itself, you can import this module and use it in a following way:
const gulp = require('gulp')
const handleCI = require('./handleCI')
const sass = require('gulp-sass')
const PRODUCTION = true // use your own system to decide if this is true or false
gulp.task('styles', handleCI((success, error) => {
return gulp.src('./scss/style.scss')
.pipe(
sass()
.on('error', error) // Add this to handle errors
)
.pipe(
gulp.dest('./styles/')
.on('error', error)
)
}, PRODUCTION))
It is perfectly valid to import from a URL inside an ES6 module and as such I've been using this technique to reuse modules between microservices that sit on different hosts/ports:
import { authInstance } from "http://auth-microservice/js/authInstance.js"
I'm approaching a release cycle and have started down my usual path of bundling to IIFEs using rollup. Rollup doesn't appear to support es6 module imports from URLs, I think it should as this is allowed in the spec :(
module-name
The module to import from. This is often a relative or absolute path name to the .js file containing the module. Certain bundlers may permit or require the use of the extension; check your environment. Only single quotes and double quotes Strings are allowed. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
I've dug through the interwebs for an hour now and have come up with nothing. Has anybody seen a resolver similar to rollup-plugin-node-resolve for resolving modules from URLs?
I had to move on from this quickly so ended up just writing a skeleton of a rollup plugin. I still feel that resolving absolute paths should be a core feature of rollup.
Updated snippet
We have been using this to transpile production code for several of our apps for a considerable amount of time now.
const fs = require('fs'),
path = require('path'),
axios = require("axios")
const createDir = path => !fs.existsSync(path) && fs.mkdirSync(path)
const mirrorDirectoryPaths = async ({ cacheLocation, url }) => {
createDir(cacheLocation)
const dirs = [], scriptPath = url.replace(/:\/\/|:/g, "-")
let currentDir = path.dirname(scriptPath)
while (currentDir !== '.') {
dirs.unshift(currentDir)
currentDir = path.dirname(currentDir)
}
dirs.forEach(d => createDir(`${cacheLocation}${d}`))
return `${cacheLocation}${scriptPath}`
}
const cacheIndex = {}
const writeToDiskCache = async ({ cacheLocation, url }) => {
//Write a file to the local disk cache for rollup to pick up.
//If the file is already existing use it instead of writing a new one.
const cached = cacheIndex[url]
if (cached) return cached
const cacheFile = await mirrorDirectoryPaths({ cacheLocation, url }),
data = (await axiosInstance.get(url).catch((e) => { console.log(url, e) })).data
fs.writeFileSync(cacheFile, data)
cacheIndex[url] = cacheFile
return cacheFile
}
const urlPlugin = (options = { cacheLocation }) => {
return {
async resolveId(importee, importer) {
//We importing from a URL
if (/^https?:\/\//.test(importee)) {
return await writeToDiskCache({ cacheLocation: options.cacheLocation, url: importee })
}
//We are importing from a file within the cacheLocation (originally from a URL) and need to continue the cache import chain.
if (importer && importer.startsWith(options.cacheLocation) && /^..?\//.test(importee)) {
const importerUrl = Object.keys(cacheIndex).find(key => cacheIndex[key] === importer),
importerPath = path.dirname(importerUrl),
importeeUrl = path.normalize(`${importerPath}/${importee}`).replace(":\\", "://").replace(/\\/g, "/")
return await writeToDiskCache({ cacheLocation: options.cacheLocation, url: importeeUrl })
}
}
}
}
This plugin together with the following config works for me:
https://github.com/mjackson/rollup-plugin-url-resolve
import typescript from "#rollup/plugin-typescript";
import urlResolve from "rollup-plugin-url-resolve";
export default {
output: {
format: "esm",
},
plugins: [
typescript({ lib: ["es5", "es6", "dom"], target: "es5" }),
urlResolve(),
],
};
You can remove the TypeScript plugin obviously.
I have a feathters.js application and now I want to secure the create and update hooks. I use a socket.io client and currently am going for JWT. I have added what I think I needed to add but am getting Error: Authentication token missing and Error Authenticating. The later I understand for that is from my code. I have a backend / frontend situation
So this is what I've implemented so far.
File: backend\backend.js (called in backend\index.js for the configuration of the app)
'use strict';
const path = require('path');
const serveStatic = require('feathers').static;
const favicon = require('serve-favicon');
const compress = require('compression');
const cors = require('cors');
const feathers = require('feathers');
const configuration = require('feathers-configuration');
const authentication = require('feathers-authentication');
const hooks = require('feathers-hooks');
const rest = require('feathers-rest');
const bodyParser = require('body-parser');
const socketio = require('feathers-socketio');
const middleware = require('./middleware/index');
const services = require('./services/index');
const appFeathers = feathers();
appFeathers.configure(configuration(path.join(__dirname, '..')));
appFeathers.use(compress())
.options('*', cors())
.use(cors())
.use(favicon(path.join(appFeathers.get('public'), 'favicon.ico')))
.use('/', serveStatic(appFeathers.get('public')))
.use(bodyParser.json())
.use(bodyParser.urlencoded({extended: true}))
.configure(hooks())
.configure(rest())
.configure(socketio())
.configure(services)
.configure(middleware)
.configure(authentication());
module.exports = appFeathers;
File: backend\config\default.json
{
"host": "localhost",
"port": 3001,
"mysql_connection": "mysql://CONNECTION_STRING",
"public": "../public/",
"auth": {
"idField": "id",
"token": {
"secret": "SECRET_KEY"
},
"local": {}
}
}
In a working component of the frontend:
<template>
<div class="vttIndex">
idnex.vue
todo: eagle.js slideshow
todo: first info
<ul>
<li v-for="message in listMessages">
{{ message }}
</li>
</ul>
</div>
</template>
<script>
import feathers from 'feathers/client';
import socketio from 'feathers-socketio/client';
import hooks from 'feathers-hooks';
import io from 'socket.io-client';
import authentication from 'feathers-authentication/client';
import * as process from "../nuxt.config";
const vttSocket = io(process.env.backendUrl);
const vttFeathers = feathers()
.configure(socketio(vttSocket))
.configure(hooks())
.configure(authentication());
const serviceMessage = vttFeathers.service('messages');
vttFeathers.authenticate({
type: 'token',
'token ': 'SECRET_KEY'
}).then(function(result){
console.log('Authenticated!', result);
}).catch(function(error){
console.error('Error authenticating!', error);
});
export default {
layout: 'default',
data: function() {
return {
listMessages: []
}
},
mounted: function() {
serviceMessage.find().then(page => {
this.listMessages = page.data;
});
serviceMessage.on('created', (serviceMessage) => {
this.listMessages.push(serviceMessage);
});
}
}
</script>
As token, I have the secret key of the backend json file. As you see, now I only try to log console messages. It is doing something for my error message is coming from there.
Question
Where am I missing what to have this functioning?
Goal
Just in case it's needed. My goal is for all 'public' data to be select with a token in my client and then an admin section maybe with 0auth. So the general 'SELECT' stuff is secured through a token instead of no authentication at all.
Solution
Okay I solved it, sort of. I first needed to create a user. Then I needed to do a local login with the user. That returns a token. If I use that, then there is no problem at all.
To use a token, you must first make sure it is generated. I was using the secret key as token what isn't correct. When you first athenticate with the 'local' type (default email and password) it will create a token and that is what you could then use with the method 'token'
The vue-router documentation does not address this topic.
Perhaps my expectation that vue-router could handle this illustrates a fundamental misunderstanding of mine of how subdomains operate.
Could this be handled by vue-router, and if so, how, and if not, why not?
I had faced this same problem while setting up multiple subdomains for a client.
As #mzgajner mentioned it's true that it is not directly possible.
But I would like to show you a simple hacky configuration which can help you setup your Vue.js application work on multiple subdomains.
You can use window.location in javascript or HTML's anchor tag to redirect your app on your subdomain. And then setup your vue-router to handle new routes.
I've made this GitHub repo which runs on 3 different subdomains.
In this GitHub repo, look at this file. It shows a simple configuration to setup different routes for different subdomains.
import Vue from 'vue';
import App from './App';
import index from './router';
import route1 from './router/route1';
import route2 from './router/route2';
Vue.config.productionTip = false;
const host = window.location.host;
const parts = host.split('.');
const domainLength = 3; // route1.example.com => domain length = 3
const router = () => {
let routes;
if (parts.length === (domainLength - 1) || parts[0] === 'www') {
routes = index;
} else if (parts[0] === 'route1') {
routes = route1;
} else if (parts[0] === 'route2') {
routes = route2;
} else {
// If you want to do something else just comment the line below
routes = index;
}
return routes;
};
/* eslint-disable no-new */
new Vue({
el: '#app',
router: router(),
template: '<App/>',
components: { App },
});
Hope this helps everyone!!!
Nope, it's not possible.
vue-router uses history.pushState, which doesn't allow you to change the origin. Quote from the docs:
The new URL must be of the same origin as the current URL; otherwise,
pushState() will throw an exception.
In other words - vue-router is a client-side router and you can't change the subdomain on the client-side (in the browser) without reloading the page.