I developed 2 custom modules, let's say module1 and module2.
module1 uses addImports (to auto-import composable and utils) and module2 uses addComponent (to, obviously, auto-import some components) along a components list in directory ./runtime/components.
// module1
addImports([
{
from: resolve(runtimeDir, 'composables/useFoo'),
name: 'useFoo',
as: 'useFoo'
}
]);
// module2
const components = fs.readdirSync(resolve('./runtime/components')).map((component: string) => {
return component.split('.').slice(0,-1).join('.');
});
// components = [ 'Component1', 'Component2' ]
components.map((component: string) => {
addComponent({
name: component,
filePath: resolve(`./runtime/components/${component}.vue`),
global: true
});
});
After publishing both and testing by installing them in a test Nuxt3 project, it appears that they work fine individualy, but as soon as I add both in nuxt.config.ts file's modules array, the first one in the array break the second one:
// In test project
// addCOmponents of module2 does not work
modules: [
'module1',
'module2'
]
// addImports of module1 does not work properly
modules: [
'module2',
'module1'
]
I have no idea what i can do or what I am doing wrong :/
Can someone help please ?
Related
My understanding is that I fall into Group 1 as those who are;
running a [nextjs] monorepo and therefore they want to be able to import their other packages from node_modules.
And running into an error similar to this:
../../node_modules/#waweb/base-ui.theme.brand-definition/dist/brand-definition.module.scss
CSS Modules cannot be imported from within node_modules. Read more:
https://nextjs.org/docs/messages/css-modules-npm Location:
../../node_modules/#waweb/base-ui.theme.brand-definition/dist/index.js
The official solution is next-transpile-modules, but as soon as I add any packages to the list of modules, I start getting errors in CSS modules in local source.
../../libs/ui/src/lib/contact.module.css
CSS Modules cannot be imported from within node_modules.
Read more: https://nextjs.org/docs/messages/css-modules-npm
Location: ../../libs/ui/src/lib/learn-more.tsx
Import trace for requested module:
../../libs/ui/src/lib/learn-more.tsx
../../libs/ui/src/lib/home.tsx
./pages/index.tsx
This is repeated for all components that were previously working.
I have prepared a branch in a public repo that has a full ci/cd and gitpod dev env configured that demonstrates the critical change.
Let's assume the sources to the components I am attempting to transpile are located in the correct node_modules dir, and I am using the following next config:
// eslint-disable-next-line #typescript-eslint/no-var-requires
const withNx = require('#nrwl/next/plugins/with-nx');
const withPlugins = require('next-compose-plugins');
const withTM = require('next-transpile-modules')(
[
'#waweb/base-ui.theme.colors',
'#waweb/base-ui.theme.color-definition',
'#waweb/base-ui.theme.size-definition',
'#waweb/base-ui.theme.shadow-definition',
'#waweb/base-ui.theme.brand-definition',
'#waweb/base-ui.theme.theme-provider',
],
{ debug: true }
);
const withPWA = require('next-pwa');
/**
* #type {import('#nrwl/next/plugins/with-nx').WithNxOptions}
**/
const nextConfig = {
nx: {
// Set this to true if you would like to to use SVGR
// See: https://github.com/gregberge/svgr
svgr: true,
},
images: {
domains: [
'www.datocms-assets.com',
'a.storyblok.com',
'images.ctfassets.net',
'images.prismic.io',
'cdn.aglty.io',
'localhost', // For Strapi
],
imageSizes: [24, 64, 300],
},
};
const pwaConfig = {};
const plugins = [[withNx], [withPWA, pwaConfig]];
module.exports = withTM(withPlugins([...plugins], nextConfig));
Any idea what's wrong with my setup here?
Thank you all for any thoughts as to what I'm doing wrong here.
Cheers!
edit
For some additional context, I have tried many different variations, and the one I ended up on (shown above) is what got the module transpilation to actually work, according to the debug statements. Only now do I have the reported errors in modules that are actually source components, not node_modules. The usage of the plugin at all seems to break unrelated functionality.
It looks odd to me that you are wrapping withPuglins inside of withTM...
withTM is a plugin so I would imagine it should be more this format:
module.exports = withPlugins([
withTM
], nextConfig);
This seems to be what's expected when looking at the docs:
https://www.npmjs.com/package/next-transpile-modules
https://www.npmjs.com/package/next-compose-plugins
I've started to develop a multi-language web application with Next JS and Lingui.js
Lingui.js is using babel so I had to install it aswell.
I've followed this tutorial https://blog.logrocket.com/complete-guide-internationalization-nextjs/
After facing some issues i've also followed the official documentation of Lingui.js https://lingui.js.org/tutorials/setup-react.html
I faced a lot of issues with babel and typescript.
But now I struggle with following error, which I could not find any help with:
wait - compiling / (client and server)...
error - ./node_modules/resolve-from/index.js:3:0
Module not found: Can't resolve 'module'
Import trace for requested module:
./node_modules/import-fresh/index.js
./node_modules/cosmiconfig/dist/loaders.js
./node_modules/cosmiconfig/dist/index.js
./node_modules/babel-plugin-macros/dist/index.js
./node_modules/#lingui/macro/index.js
./src/pages/index.tsx
https://nextjs.org/docs/messages/module-not-found
false
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
at Home (webpack-internal:///./src/pages/index.tsx:36:51)
at I18nProvider (C:\Project\app\node_modules\#lingui\react\cjs\react.development.js:46:19)
at MyApp (webpack-internal:///./src/pages/_app.tsx:48:24)
at StyleRegistry (C:\Project\app\node_modules\styled-jsx\dist\index\index.js:671:34)
at AppContainer (C:\Project\app\node_modules\next\dist\server\render.js:394:29)
at AppContainerWithIsomorphicFiberStructure (C:\Project\app\node_modules\next\dist\server\render.js:424:57)
at div
at Body (C:\Project\app\node_modules\next\dist\server\render.js:701:21)
error - Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in,
or you might have mixed up default and named imports.
here is my babel.config.js
module.exports = {
presets: [
"#babel/preset-env",
"#babel/preset-react",
"#babel/preset-typescript"
],
plugins: [
["#babel/plugin-transform-runtime",
{
"regenerator": true
}
],
[
"#babel/plugin-transform-react-jsx",
{
"runtime": "automatic"
}
],
[
'#babel/plugin-transform-runtime',
{
absoluteRuntime: false,
corejs: false,
helpers: true,
regenerator: true,
version: '7.0.0-beta.0',
},
'react-native-reanimated/plugin',
],
]
}
and my webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: ['babel-loader', 'ts-loader']
}
]
}
};
The part with React.jsx: type is invalid is because of getStaticProps in index.tsx.
So this might be an separate issue
Have you already tried the solution mentioned here ?
webpack.config.js
node: {
module: "empty",
}
I ended up deleting everything I had from Babel and lingui and copied all imports from another project which was running.
Cannot name the difference between them, but it worked afterwards.
Project:
I am working on an E-commerce application and it has more than 1,600 products and 156 categories.
Problem:
Initially, on the first product page, 30 products will be fetched (due to the page limitation), but on the left sidebar, I need filters that will be decided on the basis of tags of all 1,600 products. So that's why I need all the products in the first fetch and then I will extract common tags by looping over all the products and immediately show them on the sidebar.
What do I want?
I am not sure but I think it would be the best solution if I generate a JSON file containing all the products and store it somewhere, where I can fetch just hitting the URL using REST API in Next JS (either in getServerSideProps or getStaticProps).
Caveat:
I tried by storing JSON file in ./public directory in next js application, it worked in localhost but not in vercel.
Here is the code I wrote for storing JSON file in ./public directory:
fs.writeFileSync("./public/products.json", JSON.stringify(products, null, 2)); //all 1,600 products
One solution it to fetch it directly from front-end (if the file is not too big) otherwise, for reading the file in getServerSideProps you will need a custom webpack configuration.
//next.config.js
const path = require("path")
const CopyPlugin = require("copy-webpack-plugin")
module.exports = {
target: "serverless",
future: {
webpack5: true,
},
webpack: function (config, { dev, isServer }) {
// Fixes npm packages that depend on `fs` module
if (!isServer) {
config.resolve.fallback.fs = false
}
// copy files you're interested in
if (!dev) {
config.plugins.push(
new CopyPlugin({
patterns: [{ from: "content", to: "content" }],
})
)
}
return config
},
}
Then you can create a utility function to get the file:
export async function getStaticFile(file) {
let basePath = process.cwd()
if (process.env.NODE_ENV === "production") {
basePath = path.join(process.cwd(), ".next/server/chunks")
}
const filePath = path.join(basePath, `file`)
const fileContent = await fs.readFile(filePath, "utf8")
return fileContent
}
There is an open issue regarding this:
Next.js API routes (and pages) should support reading files
My Main goal is to create an Electron App (Windows) that locally stores data in an SQLite Database. And because of type safety I choose to use the Prisma framework instead of other SQLite Frameworks.
I took this Electron Sample Project and now try to include Prisma. Depending on what I try different problems do arrise.
1. PrismaClient is unable to be run in the Browser
I executed npx prisma generate and then try to execute this function via a button:
import { PrismaClient } from '#prisma/client';
onSqlTestAction(): void {
const prisma = new PrismaClient();
const newTestObject = prisma.testTable.create(
{
data: {
value: "TestValue"
}
}
);
}
When executing this in Electron I get this:
core.js:6456 ERROR Error: PrismaClient is unable to be run in the browser.
In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues
at new PrismaClient (index-browser.js:93)
at HomeComponent.onSqlTestAction (home.component.ts:19)
at HomeComponent_Template_button_click_7_listener (template.html:7)
at executeListenerWithErrorHandling (core.js:15281)
at wrapListenerIn_markDirtyAndPreventDefault (core.js:15319)
at HTMLButtonElement.<anonymous> (platform-browser.js:568)
at ZoneDelegate.invokeTask (zone.js:406)
at Object.onInvokeTask (core.js:28666)
at ZoneDelegate.invokeTask (zone.js:405)
at Zone.runTask (zone.js:178)
It somehow seems logical that Prisma cannot run in a browser. But I actually build a native app - with Electron that embeds a Browser. It seems to be a loophole.
2. BREAKING CHANGE: webpack < 5 used to include polyfills
So i found this Question: How to use Prisma with Electron
Seemed to be exactly what I looked for. But the error message is different (Debian binaries were not found).
The solution provided is to generate the prisma artifacts into the src folder instead of node_modules - and this leads to 19 polyfills errors. One for example:
./src/database/generated/index.js:20:11-26 - Error: Module not found: Error: Can't resolve 'path' in '[PATH_TO_MY_PROJECT]\src\database\generated'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
- install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "path": false }
And this repeats with 18 other modules. Since the error message to begin with was different I also doubt that this is the way to go.
I finally figured this out. What I needed to understand was, that all Electron apps consist of 2 parts: The Frontend Webapp (running in embedded Chromium) and a Node backend server. Those 2 parts are called IPC Main and IPC Renderer and they can communicate with each other. And since Prisma can only run on the main process which is the backend I had to send my SQL actions to the Electron backend and execute them there.
My minimal example
In the frontend (I use Angular)
// This refers to the node_modules folder of the Electron Backend, the folder where the main.ts file is located.
// I just use this import so that I can use the prisma generated classes for type safety.
import { TestTable } from '../../../app/node_modules/.prisma/client';
// Button action
onSqlTestAction(): void {
this.electronService.ipcRenderer.invoke("prisma-channel", 'Test input').then((value) => {
const testObject: TestTable = JSON.parse(value);
console.log(testObject);
});
The sample project I used already had this service to provide the IPC Renderer:
#Injectable({
providedIn: 'root'
})
export class ElectronService {
ipcRenderer: typeof ipcRenderer;
webFrame: typeof webFrame;
remote: typeof remote;
childProcess: typeof childProcess;
fs: typeof fs;
get isElectron(): boolean {
return !!(window && window.process && window.process.type);
}
constructor() {
// Conditional imports
if (this.isElectron) {
this.ipcRenderer = window.require('electron').ipcRenderer;
this.webFrame = window.require('electron').webFrame;
this.childProcess = window.require('child_process');
this.fs = window.require('fs');
// If you want to use a NodeJS 3rd party deps in Renderer process (like #electron/remote),
// it must be declared in dependencies of both package.json (in root and app folders)
// If you want to use remote object in renderer process, please set enableRemoteModule to true in main.ts
this.remote = window.require('#electron/remote');
}
}
And then in the Electron backend I first added "#prisma/client": "^3.0.1" to the package.json (for the Electron backend not the frontend). Then I added to the main.ts this function to handle the requests from the renderer:
// main.ts
ipcMain.handle("prisma-channel", async (event, args) => {
const prisma = new PrismaClient();
await prisma.testTable.create(
{
data: {
value: args
}
}
);
const readValue = await prisma.testTable.findMany();
return JSON.stringify(readValue);
})
This way of simply adding the IPC Main handler in the main.ts file of course is a big code smell but usefull as minimal example. I think I will move on with the achitecture concept presented in this article.
I'm just getting started with next-offline and found the section regarding workbox integration and its recipes.
According to the docs:
If you're new to workbox, I'd recommend reading this quick guide --
anything inside of workboxOpts will be passed to
workbox-webpack-plugin.
Define a workboxOpts object in your next.config.js and it will gets
passed to workbox-webpack-plugin. Workbox is what next-offline uses
under the hood to generate the service worker, you can learn more
about it here.
After digging around, I found this great section.
Essentially it gives a suggestion to use two different options:
GenerateSW or InjectManifest
I would like to use the InjectManifest, however when I try to implement that in my next.config.js file. I get this error:
"runtimeCaching" is not a supported parameter.
This is my next.config.js:
const withCSS = require('#zeit/next-css');
const withSass = require('#zeit/next-sass');
const withImages = require('next-images');
const optimizedImages = require('next-optimized-images');
const withOffline = require('next-offline');
module.exports = withOffline(
withImages(
optimizedImages(
withCSS(
withSass({
// useFileSystemPublicRoutes: false,
// generateSw: false, // this allows all your workboxOpts to be passed in injectManifest
generateInDevMode: true,
workboxOpts: {
swDest: './service-worker.js', // this is the important part,
exclude: [/.+error\.js$/, /\.map$/, /\.(?:png|jpg|jpeg|svg)$/],
runtimeCaching: [
{
urlPattern: /\.(?:png|jpg|jpeg|svg)$/,
handler: 'CacheFirst',
options: {
cacheName: 'hillfinder-images'
}
},
{
urlPattern: /^https?.*/,
handler: 'NetworkFirst',
options: {
cacheName: 'hillfinder-https-calls',
networkTimeoutSeconds: 15,
expiration: {
maxEntries: 150,
maxAgeSeconds: 30 * 24 * 60 * 60 // 1 month
},
cacheableResponse: {
statuses: [0, 200]
}
}
}
]
},
dontAutoRegisterSw: false,
env: {
MAPBOX_ACCESS_TOKEN: process.env.MAPBOX_ACCESS_TOKEN,
useFileSystemPublicRoutes: false
},
webpack(config, options) {
config.module.rules.push({
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000,
target: 'serverless'
}
}
});
return config;
}
})
)
)
)
);
Also when I check the Application pane, in devTools I see this:
You'll notice what appears to me a duplication of fields i.e. https-calls and hillfinder-https-calls and images and hillfinder-images.
I thought the cacheName field in the options: {} in each was allowing one to include a custom name?
Just wondering if anyone has had experience setting this up?
Thank you in advance!
(These comments apply to the basic Workbox build tools, not specifically to the next-offline wrapper, but I think they're still accurate.)
If you're using InjectManifest mode, the idea is that you write all of your service worker logic, using the underlying pieces of Workbox that you need, following a model that's similar to what's described in the Getting Started guide. You should include a call to precacheAndRoute(self.__WB_MANIFEST) somewhere in your service worker, and then the InjectManifest build tool is responsible for swapping out self.__WB_MANIFEST with an array containing the list of URLs to precache, along with revision information for each URL.
The runtimeCaching parameter is not compatible with InjectManifest. It's a parameter that can be used in GenerateSW mode, in with the Workbox build tool creates an entire service worker for you (including runtime caching routes). The GenerateSW mode takes in a declarative configuration and spits out the code for service worker based on that configuration. If that sounds good—if you'd just like to configure some build options and get a complete service worker as a result—then using GenerateSW is the right choice.