output.filename is required webpack - node.js

I tried to do the webpack exports in the following way. I tried to convert the async to sync ( regarding fs.readdir) to get the total files within directory.
const webpack = require('webpack');
const async = require('async');
const path = require('path');
const fs = require('fs');
var fileList = [];
var promiso = new Promise(function(res, rej) {
fs.readdir(__dirname + "/imports/components", function(err, files) {
files.forEach(function(file) {
console.log("file", file);
fileList.push(file);
});
let config = {
entry: {
'myPages': fileList[0]
},
module: {
loaders: [
// Javascript: js, jsx
{
test: /\.jsx?$/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: './bundler.js'
},
}
res(config)
})
});
promiso.then(function(mess) {
console.log("-------------------------mess", mess);
module.exports = mess;
});
I am getting following error
'output.filename' is required, either in config file or as --output-filename

Here you should return promise itself and then use it anywhere else. Because the require cannot work your way. Modules in Node that you load with require() are loaded synchronously and it is not possible for require to return any value that is loaded asynchronously.
module.exports = promise
And in another file use it as follows
require('path-to-file').then( (mess) => {
// Use mess
}).then(null, (err) => {
// Error handling
})

Related

Cypress publicPath not supported with percy and nock

I'm getting an issue where I am trying to add percy to my Cypress tests using nock and webpack 5. Based on a solution found here, I tried to set the publicPath to an empty string, but with no success. The error message I get is
The following error originated from your test code, not from Cypress.
Automatic publicPath is not supported in this browser
When Cypress detects uncaught errors originating from your test code
it will automatically fail the current test.
Cypress could not associate this error to any specific test.
We dynamically generated a new test to display this failure
.../webpack/runtime/publicPath:14:1
// When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration
// or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.
if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");
^
scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/");
__webpack_require__.p = scriptUrl;
In my cypress/plugins/webpack.config.js file, I have the following.
module.exports = {
resolve: { extensions: ['.ts', '.js'], fallback: { http: false } },
output: {
publicPath: '/',
},
module: {
rules: [
{
test: /\.svg$/,
use: ['#svgr/webpack'],
},
],
},
module: {
rules: [
{
test: /\.ts$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
transpileOnly: true,
},
},
],
},
};
In my cypress/plugins/index.js, I have the following.
const nock = require('nock');
const http = require('http');
const next = require('next');
const webpackPreprocessor = require('#cypress/webpack-preprocessor');
module.exports = async (on, config) => {
const app = next({ dev: true });
const handleNextRequests = app.getRequestHandler();
await app.prepare();
const customServer = new http.Server(async (req, res) => {
return handleNextRequests(req, res);
});
await new Promise((resolve, reject) => {
customServer.listen(3000, (err) => {
if (err) {
return reject(err);
}
resolve();
});
});
on('task', {
clearNock() {
nock.restore();
nock.cleanAll();
return null;
},
async nock({ hostname, method, path, statusCode, body }) {
nock.activate();
// add one-time network stub like
method = method.toLowerCase();
nock(hostname)[method](path).reply(statusCode, body);
return null;
},
});
const options = {
webpackOptions: require('./webpack.config'),
watchOptions: {},
};
on('file:preprocessor', webpackPreprocessor(options));
return config;
};
How can I configure the publicPath properly?

ESBuild error: No loader is configured for ".node" files: node_modules/sharp/build/Release/sharp.node

I am trying to make an esbuild plugin that converts GIF to PNG using Sharp but I get the following error:
❯ npx esbuild .\src\utils\gif-to-png.ts --platform=node --bundle
node_modules/sharp/lib/utility.js:7:22: error: No loader is configured for ".node" files: node_modules/sharp/build/Release/sharp.node
7 │ const sharp = require('../build/Release/sharp.node');
╵ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gif-to-png.ts
import fs from 'fs'
import path from 'path'
import sharp from 'sharp'
import { Plugin } from 'esbuild'
const ROOT_PATH = process.cwd()
const POSTS_PATH = path.join(ROOT_PATH, 'public')
function* walkSync(dir: fs.PathLike): any {
const files = fs.readdirSync(dir, { withFileTypes: true })
for (let i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
yield* walkSync(path.join(dir as string, files[i].name))
} else {
yield path.join(dir as string, files[i].name)
}
}
}
const gifToPng = async () => {
try {
for (let [i, file] of [...walkSync(POSTS_PATH)].entries()) {
const extname = path.extname(file)
if (extname === '.gif') {
console.log(file)
const dirname = path.dirname(file)
const png = path.resolve(dirname, path.basename(file).replace('.gif', '.png'))
await sharp(file).png().toFile(png)
}
}
} catch (e) {
console.error('Error thrown:', e)
}
}
export const gifToPngPlugin = (): Plugin => ({
name: 'gifToPng',
setup(build) {
build.onLoad({ filter: /\.gif$/ }, async (args) => {
const fileName = path.basename(args.path, '.gif')
let contents = await fs.promises.readFile(args.path, 'utf8')
console.log({ fileName, contents })
return {
contents,
loader: 'file',
}
})
},
})
My code is still a work in progress but I have to somehow call gifToPng function in the setup so it converts all .gif files to .png.
How do I solve the .node loader issue?
Edit:
Turns out, ESBuild doesn't support .node yet -> https://github.com/evanw/esbuild/issues/1051
I had similar issue. I added this line to my build config object. Probably better explanation in the docs: https://esbuild.github.io/content-types/#file
build({
loader: { ".node": "file" },
...
})

Why do I get an error when generating html files?

I try to read all the subfolders and files that are in the 'project/lib /viewer_lib/templates' directory, but I get an error. In cases when I try to read one file with a specific name in the folder of this directory, then I can do it. Below is the webpack code. I would be very grateful for the help.
The following code creates html files, but the generated files are not correct, i.e. They are not properly gathered in html, I need to fix it.
Project folder structure:
/Project
/assets
webpack.config.js
.babelrc
package
/js
app.js
/viewer_web
/templates
/login
login.pug
connect.pug
/main
index.pug
users.pug
/page
page.pug
/priv
/static
/js
app.js
app.css
index.html
Project
const path = require("path");
const glob = require("glob");
const fs = require("fs");
const async = require("async");
const devMode = process.env.NODE_ENV !== "production";
// styles
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
//templates
const HtmlWebpackPlugin = require("html-webpack-plugin");
const dirpath = "../lib/viewer_web/templates";
const folder = dirpath => {
const folders = fs.readdirSync(path.resolve(__dirname, dirpath));
return folders.map(name => `${dirpath}/${name}`);
};
const template = foldpath => {
return foldpath.map(path_fold => {
const files = fs.readdirSync(path.resolve(__dirname, path_fold));
return files;
});
};
const parse = template => {
const handel = template.map(array => array.map(item => {
const parts = item.split(".");
const name = parts[0];
const extension = parts[1];
return {name, extension};
}));
return handel;
};
const directories = folder(dirpath);
const files = template(directories);
const rendering = handel => {
const path_file = directories.map(item => {
const files = fs.readdirSync(path.resolve(__dirname, item));
return files.map(name => {
const templateDir = `${item}`;
return templateDir;
})
})
return handel.map(arr => arr.map(obj => {
return path_file.map(arr => arr.map(x => {
const name = obj.name;
const ext = obj.extension;
return new HtmlWebpackPlugin({
filename: `${name}.html`,
template: path.resolve(__dirname, `${x}/${name}.${ext}`),
})
}));
}));
}
const handel = parse(files);
const htmlPlugin = rendering(handel);
let a = [];
const f = htmlPlugin.map(x => x.map(y => y.map(z => z.map(t => a.push(t)))));
module.exports = (env, options) => ({
optimization: {
minimizer: [
new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: false }),
new OptimizeCSSAssetsPlugin({})
]
},
entry: {
"./js/app.js": ["./js/app.js"].concat(glob.sync("./vendor/**/*.js"))
},
output: {
filename: "app.js",
path: path.resolve(__dirname, "../priv/static/js")
},
devServer: {
port: 3000
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: "file-loader",
options: { name: "img/[name].[ext]" }
}
]
},
{
test: /\.(sass|scss)$/,
exclude: /node_modules/,
include: path.resolve(__dirname, "./scss"),
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
sourceMap: true
}
},
{
loader: "resolve-url-loader"
},
{
loader: "sass-loader",
options: {
sourceMap: true
}
}
]
},
{
test: /\.pug$/,
include: path.resolve(__dirname, '../lib/viewer_web/templates/main'),
use: ["pug-loader"]
}
]
},
plugins: [
new CopyWebpackPlugin([{ from: "static/", to: "../" }]),
new MiniCssExtractPlugin({
filename: "app.css",
allChunks: true
})
].concat(a)
});
I could not solve it this way, but the following code solved my problem.
I just wanted to divide everything into separate functions, but I got confused about it.
const dirpath = "../lib/viewer_web/templates";
function generateHtmlPlugins(templateDir) {
const templateFolds = fs.readdirSync(path.resolve(__dirname, templateDir));
return templateFolds.map(name_fold => {
const templates = fs.readdirSync(path.resolve(__dirname, `${templateDir}/${name_fold}`));
return templates.map(files => {
const parts = files.split(".");
const name = parts[0];
const extension = parts[1];
return new HtmlWebpackPlugin({
filename: `${name}.html`,
template: path.resolve(__dirname, `${templateDir}/${name_fold}/${name}.${extension}`)
});
});
});
}
const htmlPlugin = generateHtmlPlugins(dirpath);
let rendering = [];
htmlPlugin.map(x => x.map(y => rendering.push(y)));
use FLASH library , it will pass errors to view .

How to setup webpack-hot-server-middleware with vue-server-renderer and vue-router?

I'm trying to setup an own express server with webpack to use hot module replacement & server side rendering. Everything seems to work except the integration of webpack-hot-server-middleware which needs an express middleware function with (res, req, next) params - but I can't get my head around about how to implement it correctly.
This is my configuration so far:
webpack.config.js
const webpack = require('webpack');
const path = require('path');
const config = [{
name: 'client',
entry: [
'webpack-hot-middleware/client',
'./src/js/entry_client.js'
],
output: {
path: path.resolve(__dirname, 'dist/js/'),
filename: 'app.js'
},
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader'
}, {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
},
resolve: {
alias: {
vue$: 'vue/dist/vue.runtime.js'
}
}
}, {
name: 'server',
target: 'node',
entry: './src/js/entry_server.js',
output: {
path: path.resolve(__dirname, 'dist/js/'),
filename: 'app.server.js',
libraryTarget: 'commonjs2'
},
externals: require('webpack-node-externals')(),
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader'
}]
},
resolve: {
alias: {
vue$: 'vue/dist/vue.runtime.js',
}
}
}];
if (process.env.NODE_ENV !== 'production') {
config[0].plugins = [new webpack.HotModuleReplacementPlugin()];
}
module.exports = config;
entry_client.js
import {createApp} from './app';
const {app, router} = createApp();
router.onReady(() => {
app.$mount('#app');
});
entry_server.js
import {createApp} from './app';
export default context => {
return new Promise((resolve, reject) => {
const {app, router} = createApp();
router.push(context.url);
router.onReady(() => {
if (!router.getMatchedComponents().length) return reject({code: 404});
resolve(app);
}, reject);
});
};
app.js
import Vue from 'vue';
import App from '../vue/app.vue';
import {createRouter} from './router';
export function createApp() {
const router = createRouter();
const app = new Vue({
router,
render: h => h(App)
});
return {app, router};
}
router.js
import Vue from 'vue';
import Router from 'vue-router';
import Home from '../vue/home.vue';
import About from '../vue/about.vue';
Vue.use(Router);
export function createRouter() {
return new Router({
mode: 'history',
routes: [{
path: '/',
component: Home
}, {
path: '/about',
component: About
}]
});
}
server.js
const express = require('express');
const fs = require('fs');
const path = require('path');
const bundle = require('./dist/js/app.server');
const renderer = require('vue-server-renderer').createRenderer({
template: fs.readFileSync('./src/html/index.html', 'utf-8')
});
const server = express();
// add vue HMR middleware
if (process.env.NODE_ENV !== 'production') {
const webpack = require('webpack');
const compiler = webpack(require('./webpack.config'));
server.use(require('webpack-dev-middleware')(compiler, {
noInfo: true,
serverSideRender: true
}));
server.use(require('webpack-hot-middleware')(compiler.compilers.find(compiler => compiler.name === 'client')));
// server.use(require('webpack-hot-server-middleware')(compiler));
} else {
// static file serving
server.use(require('serve-favicon')(path.join(__dirname, 'src/png/favicon-32x32.png')));
server.use(express.static(path.join(__dirname, 'dist/'), {index: false}));
}
server.get('*', (req, res) => {
bundle.default({url: req.url}).then(app => {
renderer.renderToString(app, {
title: 'Some title',
description: 'Some description'
}, (err, html) => {
if (err) {
console.error('Error in renderToString:', err);
return res.status(500).send('Internal Server Error');
}
res.send(html);
});
}, err => {
if (err.code === 404) return res.status(404).send('Page not found');
console.error(err);
return res.status(500).send('Internal Server Error');
});
});
server.listen(4040);

cannot find in electron render process

I am using electron v1.2.3 with react js and es6 (with babel-preset-es2015).
I have a module where I need to import the app module in the render process. But I got this error:
Cannot read property 'app' of undefined
Here is the module that I need to import:
const app = require('electron').remote.app;
const userData = app.getPath('userData');
var nconf = require('nconf').file({file: userData + '/settings.json'});
function saveSettings(settingKey, settingValue) {
nconf.set(settingKey, settingValue);
nconf.save();
}
function readSettings(settingKey) {
nconf.load();
return nconf.get(settingKey);
}
module.exports = {
saveSettings: saveSettings,
readSettings: readSettings
};
I also have tried with
const app = require('electron').remote.require('app');
Still i get the error:
Cannot read property 'require' of undefined
Not sure is the webpack configuration matters. I am refer to this answer to setting up the webpack configuration.
module.exports = {
context: __dirname + '/app',
entry: './entry.js',
node: {
fs: "empty"
},
output: {
filename: 'bundle.js',
path: __dirname + '/build',
publicPath: 'http://localhost:8080/build/'
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'react-hot',
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/ ,
query: { presets:['es2015','react'] }
}
]
},
externals: [
(function () {
var IGNORES = [
'electron'
];
return function (context, request, callback) {
if (IGNORES.indexOf(request) >= 0) {
return callback(null, "require('" + request + "')");
}
return callback();
};
})()
]
};

Resources