NUXT: Module not found: Error: Can't resolve 'fs' - node.js

I'm starting out with vue and nuxt, I have a project using vuetify and I'm trying to modify the carousel component to dynamically load images from the static folder. So far I've come up with:
<template>
<v-carousel>
<v-carousel-item v-for="(item,i) in items" :key="i" :src="item.src"></v-carousel-item>
</v-carousel>
</template>
<script>
function getImagePaths() {
var glob = require("glob");
var options = {
cwd: "./static"
};
var fileNames = glob.sync("*", options);
var items = [];
fileNames.forEach(fileName =>
items.push({
'src': '/'+fileName
})
);
return items;
}
export default {
data() {
return {items :getImagePaths()};
}
};
</script>
When I test this I see:
ERROR in ./node_modules/fs.realpath/index.js
Module not found: Error: Can't resolve 'fs' in '....\node_modules\fs.realpath'
ERROR in ./node_modules/fs.realpath/old.js
Module not found: Error: Can't resolve 'fs' in ....\node_modules\fs.realpath'
ERROR in ./node_modules/glob/glob.js
Module not found: Error: Can't resolve 'fs' in '....\node_modules\glob'
ERROR in ./node_modules/glob/sync.js
Module not found: Error: Can't resolve 'fs' in '.....\node_modules\glob'
googling this I see a bunch of references like https://github.com/webpack-contrib/css-loader/issues/447.
These suggest that you have to midify the webpack config file with something like:
node: {
fs: 'empty'
}
I know very little about webpack. I found https://nuxtjs.org/faq/extend-webpack/ , but am not sure how to modify the webpack config file in this case.
How do I do this?

You can't use NodeJs specific module on browser.
To solve your issue, you can create an API using Nuxt server middleware. The code below, inspired by https://github.com/nuxt-community/express-template.
Create a file, index.js in api/index.js. Then fill it with:
const express = require('express')
// Create express instance
const app = express()
// Require API routes
const carousel = require('./routes/carousel')
// Import API Routes
app.use(carousel)
// Export the server middleware
module.exports = {
path: '/api',
handler: app
}
Create carousel.js in api/routes/carousel.js. Then fill it with:
const { Router } = require('express')
const glob = require('glob')
const router = Router()
router.get('/carousel/images', async function (req, res) {
const options = {
cwd: './static'
}
const filenames = glob.sync('*', options)
let items = [];
filenames.forEach(filename =>
items.push({
'src': '/'+filename
})
);
return res.json({ data: items })
})
module.exports = router
Register your server middleware in nuxt.config.js
module.exports = {
build: {
...
},
serverMiddleware: [
'~/api/index.js'
]
}
Call the api in your page / component. I assume you're using Axios here (axios-module).
<script>
export default {
async asyncData ({ $axios }) {
const images = (await $axios.$get('/api/carousel/images')).data
return { images }
}
}
</script>

I know this is an old question, but it may be helpful for someone to disable fs in their browser.
Like this:
nuxt.config.js
build: {
extend (config, { isDev, isClient }) {
config.node= {
fs: 'empty'
}
// ....
}
},

Add this in your nuxt-config.js:
build: { extend (config, { isDev, isClient }) {
config.node = {
fs: 'empty'
}
// ....
}},

Related

Fastify CLI decorators undefined

I'm using fastify-cli for building my server application.
For testing I want to generate some test JWTs. Therefore I want to use the sign method of the fastify-jwt plugin.
If I run the application with fastify start -l info ./src/app.js everything works as expected and I can access the decorators.
But in the testing setup I get an error that the jwt decorator is undefined. It seems that the decorators are not exposed and I just can't find any error. For the tests I use node-tap with this command: tap \"test/**/*.test.js\" --reporter=list
app.js
import { dirname, join } from 'path'
import autoload from '#fastify/autoload'
import { fileURLToPath } from 'url'
import jwt from '#fastify/jwt'
export const options = {
ignoreTrailingSlash: true,
logger: true
}
export default async (fastify, opts) => {
await fastify.register(jwt, {
secret: process.env.JWT_SECRET
})
// autoload plugins and routes
await fastify.register(autoload, {
dir: join(dirname(fileURLToPath(import.meta.url)), 'plugins'),
options: Object.assign({}, opts),
forceESM: true,
})
await fastify.register(autoload, {
dir: join(dirname(fileURLToPath(import.meta.url)), 'routes'),
options: Object.assign({}, opts),
forceESM: true
})
}
helper.js
import { fileURLToPath } from 'url'
import helper from 'fastify-cli/helper.js'
import path from 'path'
// config for testing
export const config = () => {
return {}
}
export const build = async (t) => {
const argv = [
path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'src', 'app.js')
]
const app = await helper.build(argv, config())
t.teardown(app.close.bind(app))
return app
}
root.test.js
import { auth, build } from '../helper.js'
import { test } from 'tap'
test('requests the "/" route', async t => {
t.plan(1)
const app = await build(t)
const token = app.jwt.sign({ ... }) //-> jwt is undefined
const res = await app.inject({
method: 'GET',
url: '/'
})
t.equal(res.statusCode, 200, 'returns a status code of 200')
})
The issue is that your application diagram looks like this:
and when you write const app = await build(t) the app variable points to Root Context, but Your app.js contains the jwt decorator.
To solve it, you need just to wrap you app.js file with the fastify-plugin because it breaks the encapsulation:
import fp from 'fastify-plugin'
export default fp(async (fastify, opts) => { ... })
Note: you can visualize this structure by using fastify-overview (and the fastify-overview-ui plugin together:

get all routes from nest.js app from a script

Currently i save all my routes in a file after the projects starts
async function bootstrap() {
const adapter = new FastifyAdapter(fastifyInstance);
adapter.register(fastifyMultipart, fastifyAdapterConfig);
const app = await NestFactory.create<NestFastifyApplication>(AppModule, adapter);
// Collecting all the routes from the project
const routesList: Array<{ method: string; url: string }> = [];
app
.getHttpAdapter()
.getInstance()
.addHook('onRoute', (route: Record<string, string>) => {
if (!JSON.stringify(route).includes('"hide":true')) {
routesList.push({ method: <string>route.method, url: <string>route.url });
}
});
// Saving all routes into a file in a root of a project
const routesFileName = 'mock_index.js';
fs.writeFile(path.join(process.cwd(), routesFileName), JSON.stringify(routesList), (err) => {
if (err) {
logger.error(`File ${routesFileName} saving errors: ${JSON.stringify(err)}`);
throw err;
}
logger.log(`Routes list is saved in a root folder in a file: ${routesFileName}`);
});
}
But how can I save all my routes without starting a project, outside bootstrap()
for example from yarn:generate-routes.
"generate-routes": "node ./ci-cd/generate-routes.js",
The main problem is to get the list of routes in runtime.

RequireJS + Mocha + JSDom + Node -> Shim config not supported in Node

I'm trying to setup a Mocha testing framework using JSDom with RequireJS. Because I'm running the test on node instead of using a browser (since I'm using JSDom), all the non AMD modules doesn't seem to be imported and is throwing Shim config not supported in Node. Does anyone know how I can export those modules to AMD or what the right approach is? (aka what I'm doing wrong)
Example of my set-up
Component.js
define(["jquery", "non_AMD_Module", ... ], function($, NonAMDModule, ...) {
let component = {
...
foo = () => {
NonAMDModule.bar();
};
};
return component;
});
Component.test.js
const requirejs = require('requirejs');
const { JSDOM } = require('jsdom');
requirejs.config({
baseUrl: "dist/app",
paths: {
jquery: "lib/jquery",
component: "path_to_component",
non_AMD_Module: "path_to_module"
},
shim: {
non_AMD_Module: { exports: "non_AMD_Module" } // This doesn't work
}
});
const { window } = new JSDOM("<html></html>");
global.window = window;
global.document = window.document;
global.$ = requirejs('jquery');
const Component = requireJS('component');
describe('test', () => {
it('is a simple test', () => {
const testComponent = new Component();
testComponent.foo();
}
});
When I run the test suite, I get:
Mocha Exploded!
TypeError: Cannot read property 'bar' of undefined
running r.js -convert "path_to_module" did not work for this module
Looking at the source code for jQuery, I found that there's this boiler-plate coded that exports it to AMD.
This can be added at the bottom of the non-AMD-module in order to export it to an AMD module accessible by RequireJS
if ( typeof define === "function" && define.amd ) {
define([], function {
return non_AMD_Module;
});
}
Other Resources:
Shim a module in Require.js that uses module.exports possible?
https://github.com/requirejs/requirejs/wiki/Updating-existing-libraries#anon

Next.js - using BigQuery client library gives an error : Module not found: Can't resolve 'child_process'

I am trying to query bigQuery dataset from a next.js project.
I have installed #google-cloud/bigquery and followed the steps from here
I have also tried next.js related solutions from this link but still getting below error.
It looks like next.config.js needs to be configured for this to allow this api call. I am not sure what needs to be changed.
Could someone please help me resolve this issue?
here is my code :
const { BigQuery } = require("#google-cloud/bigquery");
const bigquery = new BigQuery();
useEffect(() => {
async function queryBigQuery() {
const query = `
SELECT fieldname
FROM \`db.dataset.tablename\` WHERE columnname = 50
LIMIT 10`;
const options = {
query: query,
};
// Run the query
const [rows] = await bigquery.query(options);
console.log("Query Results:");
rows.forEach((row) => {
const url = row["url"];
const viewCount = row["view_count"];
console.log(`url: ${url}, ${viewCount} views`);
});
}
queryBigQuery();
}, []);
**wait - compiling...
error - ./node_modules/google-auth-library/build/src/auth/googleauth.js:17:0
Module not found: Can't resolve 'child_process'**
UPDATED:
I am able to load bigQuery library I think on client side but its giving me new error.
Here is my latest next.config.js file
module.exports = {
webpack: (config, { isServer, webpack }) => {
if (!isServer) {
config.node = {
dgram: "empty",
fs: "empty",
net: "empty",
tls: "empty",
child_process: "empty",
};
}
return config;
},
env: {
project variables.
};
New Error:
#google-cloud/bigquery is meant to run on a Node.js environment, it won't work in the browser.
You'll need to move your code to a data fetching method like getStaticProps/getServerSideProps or to an API route, as they all run server-side.
Here's an example using an API route, as it seems to fit your use-case best.
// pages/api/bigquery
const { BigQuery } = require("#google-cloud/bigquery");
const bigquery = new BigQuery();
export default function handler(req, res) {
const query = `
SELECT fieldname
FROM \`db.dataset.tablename\` WHERE columnname = 50
LIMIT 10
`;
const options = {
query: query,
};
// Run your query/logic here
res.json(data); // Return your JSON data after logic has been applied
}
Then, in your React component's useEffect:
const queryBigQuery = async () => {
const res = await fetch('api/bigquery');
const data = await res.json(); // Returns JSON data from API route
console.log(data);
}
useEffect(() => {
queryBigQuery();
}, []);

Query parameters in express 4 give me a "No default engine was specified" error

I am developing a web app using the MEAN stack (no Mongo for now)
I am trying to pass the name of a file on the server using a query paramerer, the error happens when i get :
"localhost:8080/api/result?filename=for-debug-file-name"
It is working well if I remove the console.log() right below
But when I get the query parameter it gets me the "Error: No default engine was specified and no extension was provided”.
(This route correspond to api/result)
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
console.log(req.query('filename')); // ERROR
res.status(200).json({ "json-test": 42 });
})
module.exports = router;
Here are my angular routes :
const appRoutes: Routes = [
{
path: 'result',
component: ResultComponent,
},
{
path: 'upload',
component: UploaderComponent,
},
{
path: '',
redirectTo: '/upload',
pathMatch: 'full'
}];
And here is my ResultComponent.ts :
ngOnInit() {
this.getParsedDocumentData('for-debug-file-name');
}
getParsedDocumentData(fileName: string): Observable<string[]> {
let params = new URLSearchParams();
params.append('filename', fileName);
let options = new RequestOptions({ params: params });
return this.http.get('http://localhost:8080/api/result/', options)
.map(res => res.json())
.catch(this.handleError);
}
private handleError (error: any) {
return Observable.throw(error);
}
I would really appreciate your help as I have been stuck for 4 hours.
Thanks.
query method in request object does not exists. Instead use query property to access filename parameter.
console.log(req.query.filename);
Reference

Resources