How to combine the modules of the webpack through the merge function? - node.js

Through the merge function, in case the version of the web park is development, I try to add a server file to it only in this case. Writes an error. He writes that the types are not correct, but I indicated the same type in both interfaces
An argument of type "Devserver" cannot be assigned to a parameter of type "IgetConfig". The "entry" property is missing in the "I dev Server" type and is mandatory in the "I get Config" type.
return merge(mainConfig, serverTuning);
file dev.config.ts
module.exports = {
devServer: {
port: 3000,
},
};
file webpack config
import { merge } from 'webpack-merge';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import { PlatformPath } from 'path';
const path: PlatformPath = require('path');
interface IdevServer {
devServer: {
port: number;
};
}
const serverTuning: IdevServer = require('./dev.config');
const test = 'main';
const ROOT_DIRECTORY = path.resolve(__dirname, '..');
interface IgetConfig {
entry: {
main: string[];
};
devServer?: {
port: number;
};
}
const getConfig = (mode): IgetConfig => {
const isProduction = mode === 'production';
const isDevelopment = mode === 'development';
return {
entry: {
[test]: ['./src/index.js'],
},
};
};
module.exports = (env, { mode }) => {
const mainConfig = getConfig(mode);
if (mode === 'development') {
return merge(mainConfig, serverTuning);
}
return mainConfig;
};
module.exports = (env, { mode }) => {
const mainConfig = getConfig(mode);
if (mode === 'development') {
return merge(mainConfig, serverTuning);
}
return mainConfig;
};

Related

Why is my _middleware not able to route well in production (NEXTJS)?

I have the following on my _middleware.ts file with the objective of mainly routing requests to mysubdomain. Its working well on my local server but when I deploy to vercel its throwing a 404. Any help will be much appreciated.
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { request } from "http";
export default function middleware(req: NextRequest) {
// Clone the request url
const newReq = req.nextUrl.clone();
const regex = new RegExp(`\.subdomaingivenbyvercel-[\w\w\w\w\w\w\w\w\w]-username\.vercel\.app`);
const pathname = req.nextUrl.pathname.toString();
// Get hostname of request (e.g. demo.vercel.pub)
const hostname = req.headers.get("host");
if (!hostname)
return new Response(null, {
status: 400,
statusText: "No hostname found in request headers"
});
const currentHost =
process.env.VERCEL_ENV === `production` && process.env.VERCEL === `1`
? // You have to replace ".vercel.pub" with your own domain if you deploy this
example under your domain.
// You can use wildcard subdomains on .vercel.app links that are associated
with your Vercel team slug
// in this case, our team slug is "platformize", thus
*.platformize.vercel.app works
hostname
.replace(`.myrootdomain.com`, "")
.replace(`.branchname.vercel.app`, "")
.replace(`.*.vercel.app`, "")
.replace(regex, "")
: hostname.replace(`.localhost:3000`, "");
if (pathname.startsWith(`/_sites`))
return new Response(null, {
status: 404
});
if (
!pathname.includes(".") &&
!pathname.startsWith("/api")
) {
if (currentHost === "mysubdomain") {
if (
pathname === "/login" &&
(req.cookies["next-auth.session-token"] ||
req.cookies["__Secure-next-auth.session-token"])
) {
newReq.pathname = "/";
return NextResponse.redirect(newReq.toString());
}
newReq.pathname = `/mysubdomain${pathname}`;
return NextResponse.rewrite(newReq.toString());
}
newReq.pathname = `${pathname}`;
return NextResponse.rewrite(newReq.toString());
}
}
I try all of the routes and none of them can be found. I have tried everything around the way the middleware parses the URL without success. Here you can see my next.config.js just in case Im doing a redirect without knowing it:
/**
* #type {import('next').NextConfig}
*/
const plugins = require("next-compose-plugins");
const withBundleAnalyzer = require("#next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true"
});
const withOffline = require("next-offline");
function esbuildLoader(config, options) {
const jsLoader = config.module.rules.find(
(rule) => rule.test && rule.test.test(".js")
);
if (jsLoader && jsLoader.use) {
if (jsLoader.use.length > 0) {
jsLoader.use.forEach((e) => {
e.loader = "esbuild-loader";
e.options = options;
});
} else {
jsLoader.use.loader = "esbuild-loader";
jsLoader.use.options = options;
}
}
}
// the config break if we use next export
const nextConfig =
process.env.EXPORT !== "true"
? {
webpack(config, { webpack, dev, isServer }) {
config.plugins.push(
new webpack.ProvidePlugin({
React: "react"
})
);
// audio support
config.module.rules.push({
test: /\.(ogg|mp3|wav|mpe?g)$/i,
exclude: config.exclude,
use: [
{
loader: require.resolve("url-loader"),
options: {
limit: config.inlineImageLimit,
fallback: require.resolve("file-loader"),
publicPath: `${config.assetPrefix}/_next/static/images/`,
outputPath: `${isServer ? "../" : ""}static/images/`,
name: "[name]-[hash].[ext]",
esModule: config.esModule || false
}
}
]
});
config.module.rules.push({
test: /\.(glsl|vs|fs|vert|frag)$/,
exclude: /node_modules/,
use: ["raw-loader", "glslify-loader", "#svgr/webpack"]
});
config.module.rules.push({
test: /\.svg$/,
use: [`#svgr/webpack`]
});
return config;
},
images: {
domains: [
"lomplay.com/ipfs",
"nft.storage",
"avatars.githubusercontent.com"
]
},
reactStrictMode: true,
swcMinify: false // Required to fix: https://nextjs.org/docs/messages/failed-
loading-swc
}
: {};
module.exports = plugins(
[
[
withOffline,
{
workboxOpts: {
swDest: process.env.NEXT_EXPORT
? "service-worker.js"
: "static/service-worker.js",
runtimeCaching: [
{
urlPattern: /^https?.*/,
handler: "NetworkFirst",
options: {
cacheName: "offlineCache",
expiration: {
maxEntries: 200
}
}
}
]
},
async rewrites() {
return {
beforeFiles: [
{
source: "/_subdomain/api/newsletter",
destination: "https://rootdomain.com/api/newsletter"
}
],
afterFiles: [
{
source: "/service-worker.js",
destination: "/_next/static/service-worker.js"
}
]
};
}
}
],
withBundleAnalyzer
],
nextConfig
);

Auth0 with Electron working in development but not when packaged

Im using Auth0 in an electron app to manage a log-in system. I referenced this tutorial here:
https://auth0.com/blog/securing-electron-applications-with-openid-connect-and-oauth-2/
to get started with using it.
Auth0 has been working great when I've been working in development but for some reason fails after I call "yarn package" to build the app. My electron app used electron-react-boilerplate (https://github.com/electron-react-boilerplate/electron-react-boilerplate).
Here are the important files:
// imports
...
import {
getAuthenticationURL,
refreshTokens,
loadTokens,
logout,
getLogOutUrl,
getProfile,
getResponse,
} from './services/authservice';
export default class AppUpdater {
constructor() {
...
}
}
let mainWindow: BrowserWindow | null = null;
if (process.env.NODE_ENV === 'production') {
const sourceMapSupport = require('source-map-support');
sourceMapSupport.install();
}
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
require('electron-debug')();
}
const installExtensions = async () => {
...
};
const createWindow = async () => {
console.log('now starting the main process');
if (
process.env.NODE_ENV === 'development' ||
process.env.DEBUG_PROD === 'true'
) {
await installExtensions();
}
const RESOURCES_PATH = app.isPackaged
? path.join(process.resourcesPath, 'assets')
: path.join(__dirname, '../assets');
const getAssetPath = (...paths: string[]): string => {
return path.join(RESOURCES_PATH, ...paths);
};
mainWindow = new BrowserWindow({
show: true,
width: 1024,
height: 728,
titleBarStyle: 'hidden', // add this line
frame: false,
//icon: getAssetPath('icon.png'),
webPreferences: {
nodeIntegration: true,
},
});
mainWindow.loadURL(`file://${__dirname}/index.html`);
const devtools = new BrowserWindow();
mainWindow.webContents.setDevToolsWebContents(devtools.webContents);
mainWindow.webContents.openDevTools({ mode: 'detach' });
};
/**
* Add event listeners...
*/
let win = null;
function createAuthWindow() {
destroyAuthWin();
win = new BrowserWindow({
width: 1000,
height: 600,
webPreferences: {
nodeIntegration: false,
enableRemoteModule: false,
},
});
console.log(getAuthenticationURL());
win.loadURL(getAuthenticationURL());
const {
session: { webRequest },
} = win.webContents;
const filter = {
urls: [
'file:///callback*',
],
};
webRequest.onBeforeRequest(filter, async ({ url }) => {
console.log(url);
await loadTokens(url)
.then((res) => {
console.log(res);
})
.catch(console.log);
console.log('from web request');
createWindow();
return destroyAuthWin();
});
win.on('authenticated', () => {
console.log('WE HAVE AUTHENTICATED');
destroyAuthWin();
});
win.on('closed', () => {
win = null;
});
}
function destroyAuthWin() {
if (!win) return;
win.close();
win = null;
}
// logout logic: removed for simplicity
ipcMain.on('profileRequest', (event, arg) => {
//event.reply('profileResponse', getProfile());
event.returnValue = getProfile();
});
const showWindow = async () => {
try {
await refreshTokens();
return createWindow();
} catch (err) {
createAuthWindow();
}
};
this is my auth services file:
let accessToken = null;
let profile = {};
let refreshToken = null;
export function getAccessToken() {
return accessToken;
}
export function getProfile() {
return profile;
}
export function getAuthenticationURL() {
return (
'https://' +
auth0Domain +
'/authorize?' +
'scope=openid%20profile%20offline_access&' +
'response_type=code&' +
'client_id=' +
clientId +
'&' +
'redirect_uri=' +
redirectUri
);
}
export async function refreshTokens() {
const refreshToken = await keytar.getPassword(keytarService, keytarAccount);
if (refreshToken) {
const refreshOptions = {
method: 'POST',
url: `https://${auth0Domain}/oauth/token`,
headers: { 'content-type': 'application/json' },
data: {
grant_type: 'refresh_token',
client_id: clientId,
refresh_token: refreshToken,
},
};
try {
const response = await axios(refreshOptions);
res = response;
accessToken = response.data.access_token;
profile = jwtDecode(response.data.id_token);
} catch (error) {
await logout();
throw error;
}
} else {
throw new Error('No available refresh token.');
}
}
export async function loadTokens(callbackURL) {
console.log('loading tokens:');
console.log(callbackURL);
res = callbackURL;
const urlParts = url.parse(callbackURL, true);
const query = urlParts.query;
console.log(query);
const exchangeOptions = {
grant_type: 'authorization_code',
client_id: clientId,
code: query.code,
redirect_uri: redirectUri,
};
const options = {
method: 'POST',
url: `https://${auth0Domain}/oauth/token`,
headers: {
'content-type': 'application/json',
},
data: JSON.stringify(exchangeOptions),
};
try {
const response = await axios(options);
console.log('from token:');
console.log(response);
res = response;
accessToken = response.data.access_token;
profile = jwtDecode(response.data.id_token);
refreshToken = response.data.refresh_token;
console.log(getProfile());
if (refreshToken) {
await keytar.setPassword(keytarService, keytarAccount, refreshToken);
}
} catch (error) {
await logout();
throw error;
}
}
I have a file in my components folder called "Auth.jsx" which has a "get profile" methods which interacts with the main process to get the profile
const getProfile = () => {
return ipcRenderer.sendSync('profileRequest', true);
};
After I package the electron app, the getProfile method always returns null/undefined.
Here are the auth0 logs:
Auth0 Logs
It shows that there is a successful Login and Exchange.
Finally, here's my webpack file: "webpack.config.main.prod.babel"
/**
* Webpack config for production electron main process
*/
import path from 'path';
import webpack from 'webpack';
import { merge } from 'webpack-merge';
import TerserPlugin from 'terser-webpack-plugin';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import baseConfig from './webpack.config.base';
import CheckNodeEnv from '../scripts/CheckNodeEnv';
import DeleteSourceMaps from '../scripts/DeleteSourceMaps';
import dotenv from 'dotenv';
CheckNodeEnv('production');
DeleteSourceMaps();
const devtoolsConfig =
process.env.DEBUG_PROD === 'true'
? {
devtool: 'source-map',
}
: {};
export default merge(baseConfig, {
...devtoolsConfig,
mode: 'production',
target: 'electron-main',
entry: './src/main.dev.ts',
output: {
path: path.join(__dirname, '../../'),
filename: './src/main.prod.js',
},
optimization: {
minimizer: [
new TerserPlugin({
parallel: true,
}),
],
},
plugins: [
new BundleAnalyzerPlugin({
analyzerMode:
process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled',
openAnalyzer: process.env.OPEN_ANALYZER === 'true',
}),
new webpack.EnvironmentPlugin({
NODE_ENV: 'production',
DEBUG_PROD: true,
START_MINIMIZED: false,
/*
other environment variables, including auth0 domain name and clientID
*/
}),
],
/**
* Disables webpack processing of __dirname and __filename.
* If you run the bundle in node.js it falls back to these values of node.js.
* https://github.com/webpack/webpack/issues/2010
*/
node: {
__dirname: false,
__filename: false,
},
});
Im suspecting the problem might have something to do with webpack since it's only the packaged version of the application that doesn't work properly. Im not sure exactly what the problem is, whether is a problem in the code or if I need to specifically change something within my Auth0 dashboard. If you have any suggestions or any ideas on how to debug let me know!
I had the exact same issue! I fixed it by changing the import method for jwt-decode from require to import
import jwtDecode from 'jwt-decode'

Redux applyMiddleware multiple usage problem with inmutable array

I creating a Next.js & Redux app. I using multiple middleware for redux. I have bindMiddleware function for checking development environment and apply development middlewares.
import { createStore, applyMiddleware, combineReducers } from "redux";
import thunkMiddleware from "redux-thunk";
import promiseMiddleware from "redux-promise-middleware";
const bindMiddleware = (middleware) => {
if (process.env.NODE_ENV !== "production") {
const { composeWithDevTools } = require("redux-devtools-extension");
const loggerMiddleware = require("redux-logger");
return composeWithDevTools(
applyMiddleware([...middleware, loggerMiddleware])
);
}
return applyMiddleware(...middleware);
};
bindMiddleware([thunkMiddleware, promiseMiddleware])
My app not working because of this code:
return composeWithDevTools(
applyMiddleware([...middleware, loggerMiddleware])
);
If I use this code instead of the bad code, it won't give an error.
return composeWithDevTools(
applyMiddleware(...middleware)
);
!!! FIXED !!!
const bindMiddleware = (middleware) => {
if (process.env.NODE_ENV !== "production") {
const { composeWithDevTools } = require("redux-devtools-extension");
const { logger } = require("redux-logger"); // edited
return composeWithDevTools(applyMiddleware(...middleware, logger)); // edited
}
return applyMiddleware(...middleware);
};
const bindMiddleware = (middleware) => {
if (process.env.NODE_ENV !== "production") {
const { composeWithDevTools } = require("redux-devtools-extension");
const { logger } = require("redux-logger"); // edited
return composeWithDevTools(applyMiddleware(...middleware, logger)); // edited
}
return applyMiddleware(...middleware);
};

How to detect which compiling option are used on recompilation by webpack

I have the following script
const WebpackDevServer = require('webpack-dev-server')
const webpack = require('webpack')
const electroner = require('electroner')
const packageJson = require('../package')
const config = require('./webpack.config')
const options = {
port: 3000,
contentBase: './dist',
hot: true,
overlay: true,
after: function (app, server) {
const window = electroner(`${__dirname}/../${packageJson.main}`, {
'enable-transparent-visuals': true,
'disable-cpu': true
})
window.on('close', () => {
server.close()
})
},
stats: 'errors-only'
}
WebpackDevServer.addDevServerEntrypoints(config, options)
const compiler = webpack(config)
const server = new WebpackDevServer(compiler, options)
server.listen(3000, 'localhost', () => {
console.log('dev server listening on port 3000')
})
The "config" variable contains/points to two webpack configuration (one for main and another for renderer script for an electron app).
What I'd like to achieve is, I want to restart the electron process only when the recompilation of the main script is successful.
I've read for a week about hooks but I believe they do not help in achieving the above.
I am looking for a solution that goes along like this:
compiler.on('compile', (stats) => {
if(stats.details === 'main.js'){
// logic to restart electron process here.
}
})
Any hints would be appreciated.
Achieved the behavior I was looking for with the below
const webpackDevServer = require('webpack-dev-server')
const webpack = require('webpack')
const electroner = require('electroner')
const path = require('path')
const packageJson = require('./package')
const config = require('./webpack.config')
let window
let server
const options = {
contentBase: './dist',
hot: true,
host: 'localhost',
after: function (app, server) {
window = electroner(path.resolve(__dirname, packageJson.main), {
'enable-transparent-visuals': true,
'disable-cpu': true
})
window.on('close', () => {
server.close()
})
},
port: 3000,
overlay: true,
stats: 'errors-only',
writeToDisk: true
}
let done = false
function initCompiler () {
done = false
webpackDevServer.addDevServerEntrypoints(config, options)
const compiler = webpack(config, (error, stats) => {
if (error) {
console.error(error.stack || error)
if (error.details) {
console.error(error.details)
}
return
}
const info = stats.toJson()
if (stats.hasErrors()) {
console.error(info.errors)
}
if (stats.hasWarnings()) {
console.warn(info.warnings)
}
done = true
})
let check
let start = () => {
if (!done) {
check = setTimeout(start, 100)
return
}
server = new webpackDevServer(compiler, options)
server.listen(3000, 'localhost', () => {
console.log('dev server listening on port 3000')
})
}
setTimeout(start, 100)
let files = []
compiler.hooks.watchRun.tap('MainProcess', compiler => {
files = Object.keys(compiler.watchFileSystem.watcher.mtimes).map(file => {
return path.parse(file).dir
})
})
compiler.hooks.done.tap('MainProcess', () => {
const search = path.resolve(__dirname, 'src', 'main')
if (files.length && files.filter(file => file.indexOf(search) > -1).length) {
files = []
window.kill()
server.close()
initCompiler()
}
})
}
initCompiler()
Edit
My previous answer had some issues. On compile, if the main.js file wasn't already present, it would error and stop the compilation and not start the app.
The edit ensures that the compile is first completed before starting the server and then start the electron app.

Nextjs config file - how to export more content

I am trying edit nextjs config file. To use ant design and i18next.
For ant design i need this.
/* eslint-disable */
const withCss = require('#zeit/next-css')
module.exports =
withCss({
webpack: (config, {
isServer
}) => {
if (isServer) {
const antStyles = /antd\/.*?\/style\/css.*?/
const origExternals = [...config.externals]
config.externals = [
(context, request, callback) => {
if (request.match(antStyles)) return callback()
if (typeof origExternals[0] === 'function') {
origExternals[0](context, request, callback)
} else {
callback()
}
},
...(typeof origExternals[0] === 'function' ? [] : origExternals),
]
config.module.rules.unshift({
test: antStyles,
use: 'null-loader',
})
}
return config
},
})
And for i18next i need
module.exports = {
publicRuntimeConfig: {
localeSubpaths: typeof process.env.LOCALE_SUBPATHS === 'string'
? process.env.LOCALE_SUBPATHS
: 'none',
},
}
So i combined it into:
/* eslint-disable */
const withCss = require('#zeit/next-css')
module.exports = ({
publicRuntimeConfig: {
localeSubpaths: typeof process.env.LOCALE_SUBPATHS === 'string' ?
process.env.LOCALE_SUBPATHS : 'none',
}
}, withCss({
webpack: (config, {
isServer
}) => {
if (isServer) {
const antStyles = /antd\/.*?\/style\/css.*?/
const origExternals = [...config.externals]
config.externals = [
(context, request, callback) => {
if (request.match(antStyles)) return callback()
if (typeof origExternals[0] === 'function') {
origExternals[0](context, request, callback)
} else {
callback()
}
},
...(typeof origExternals[0] === 'function' ? [] : origExternals),
]
config.module.rules.unshift({
test: antStyles,
use: 'null-loader',
})
}
return config
},
}))
But I am not sure if is it the correct way how to do it because I am still getting an error (ant design works alright and I am trying to import i18next)
D:\xxx\xxx\nextcms\i18n.js:4
} = require('next/config').default().publicRuntimeConfig
^
TypeError: Cannot read property 'publicRuntimeConfig' of undefined
It can be caused by some other problem but I just need to know if I am correctly exporting those ant design with i18next.
Thank for your time.
You need to wrap your entire export using withCss().
Try this instead:
/* eslint-disable */
const withCss = require('#zeit/next-css')
module.exports = withCss({
publicRuntimeConfig: {
// ...
},
webpack: (config, { isServer }) => {
// ...
return config
},
})

Resources