how to setup antd less support with nextjs 12 - next.js

im trying to setup nextjs 12 with ant design antd and in next.config.js when i try to setup withAntdLess it gives type error
Type '{}' is missing the following properties from type '{ esModule: boolean; sourceMap: boolean; modules: { mode: string; }; }': esModule, sourceMap, modules
although all props are optional according to next-plugin-antd-less docs
next.config.js file:
// #ts-check
// next.config.js
const withAntdLess = require('next-plugin-antd-less');
/**
* #type {import('next').NextConfig}
**/
module.exports =withAntdLess({
cssLoaderOptions: {},
// Other Config Here...
webpack(config) {
return config;
},
reactStrictMode: true,
});

I solved it using next-with-less https://github.com/elado/next-with-less
next.config.js
const withLess = require('next-with-less');
const lessToJS = require('less-vars-to-js');
const themeVariables = lessToJS(
fs.readFileSync(
path.resolve(__dirname, './public/styles/custom.less'),
'utf8'
)
);
module.exports = withLess({
...
lessLoaderOptions: {
lessOptions: {
javascriptEnabled: true,
modifyVars: themeVariables, // make your antd custom effective
localIdentName: '[path]___[local]___[hash:base64:5]',
},
},
...
})
Import your custom less file on top off the file _app.jsx
import 'public/styles/custom.less';
...
Import the default Antd less file on your custom less file: (in my case public/styles/custom.less)
#import "~antd/dist/antd.less";
....
Extra notes:
If you have an old implementation of Antd, you should remove the integration in your .babelrc
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "lib",
"style": true
}
],
If you have an old implementation of Antd, you should remove the integration in your webpack zone in your next.config.js
if (isServer) {
const antStyles = /antd\/.*?\/style.*?/;
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',
});
}

Related

Error when use remote components with hooks and module federations with nextjs

I receive this error when use hooks in component from remote app when
enter image description here
i use now nextjs13 with module federations
how to resolve this
enter code here
my component remote app
'use client'
import { useState } from 'react'
export default function Button() {
const [count, setCount] = useState(0)
return (
<div>
<button onClick={() => setCount(count + 1)}>adicionar</button>
<h1>{count}</h1>
</div>
)
}
my component in host
'use client'
import dynamic from 'next/dynamic'
import React, { useState } from 'react'
const RemoteComponent = dynamic({
loader: async () => {
const { default: RemoteComponent } = await import('front_login/Button')
return () => <RemoteComponent />
},
})
export default function Auth() {
return (
<>
<RemoteComponent />
</>
)
}
my next-config.js in host
const { NextFederationPlugin } = require('#module-federation/nextjs-mf')
/** #type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
experimental: {
appDir: true,
},
webpack: (config, options) => {
const { isServer } = options
Object.assign(config.experiments, { topLevelAwait: true })
config.watchOptions = {
poll: 1000,
aggregateTimeout: 300,
}
config.plugins.push(
new NextFederationPlugin({
name: 'front_gateway',
remotes: {
front_login: `front_login#${process.env.FRONT_LOGIN}/_next/static/${
isServer ? 'ssr' : 'chunks'
}/remoteEntry.js`,
},
filename: 'static/chunks/remoteEntry.js',
shared: {
'styled-components': {
requiredVersion: false,
eager: true,
singleton: true,
},
},
}),
)
return config
},
}
module.exports = nextConfig
my next config in remote app
/** #type {import('next').NextConfig} */
const { NextFederationPlugin } = require('#module-federation/nextjs-mf')
const nextConfig = {
output: 'standalone',
experimental: {
appDir: true,
},
webpack: (config, options) => {
const { isServer } = options
config.watchOptions = {
poll: 1000,
aggregateTimeout: 300,
}
config.plugins.push(
new NextFederationPlugin({
name: 'front_login',
remotes: {
front_gateway: `front_gateway#${
process.env.FRONT_GATEWAY
}/_next/static/${isServer ? 'ssr' : 'chunks'}/remoteEntry.js`,
},
filename: 'static/chunks/remoteEntry.js',
exposes: {
'./Button': './src/app/components/Button/button.tsx',
'./Doidao': './src/app/doidao/page.tsx',
},
shared: {
'styled-components': {
singleton: true,
eager: true,
requiredVersion: false,
},
},
}),
)
return config
},
}
module.exports = nextConfig
Please i need help to fix this
When use remote component in remote app, work with success but in host not working

NX Nextjs Micro frontend

I am using nx.dev for maintaining monorepo, my project demands MFE with Nextjs.
Following #module-federation/nextjs-mf it says it is moved to paid plugin, still i want some solution with open code (without #module-federation/nextjs-mf plugin).
I tried to configure webpack property for ModuleFedration which is generating remoteEntry file. but still it is not getting in my browser network calls.
How can i make it available for public access ?
I tried to change the publicPath for webpack, but still it is same.
next.config.js
// eslint-disable-next-line #typescript-eslint/no-var-requires
const withNx = require('#nrwl/next/plugins/with-nx');
/**
* #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: false,
},
distDir: 'build',
webpack:(config, options) =>{
config.plugins.push(
new options.webpack.container.ModuleFederationPlugin({
name:"fe2",
filename:'remoteEntry_2.js',
remoteType:"var",
exposes:{
"./remote2":"./components/hello.tsx"
},
shared:[
{
react: {
eager: true,
singleton: true,
requiredVersion: false,
}
},
{
"react-dom": {
eager: true,
singleton: true,
requiredVersion: false,
}
}
]
})
)
return {
output: {
...config.output,
publicPath: 'http://localhost:4002/',
},
...config
};
}
};
module.exports = withNx(nextConfig);
remoteEntry is getting generated in build dir
RemoteEntry is not there in browser's network
I am a bit in the same case as you, was not understanding why it's not showing up on the network.
When running the nextjs app, you cannot access static that are directly on you build folder output, you have to put them in the static folder of your output folder (that was my conclusion)
Here how the nextjs configs looks
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
productionBrowserSourceMaps: true,
distDir: 'build',
webpack: (config, context) => {
return {
...config,
experiments: {
...config.experiments,
topLevelAwait: true,
},
plugins: config.plugins.concat(
new context.webpack.container.ModuleFederationPlugin({
name: 'microfrontend',
filename: 'static/chunks/remotes.js', // this is where the magic happen
remoteType: 'var',
exposes: {
// expose all component here.
'./component1': path.resolve(process.cwd(), './src/components/component1'),
'./component2': path.resolve(process.cwd(), './src/components/component2'),
},
shared: {
react: {
singleton: true,
strictVersion: true,
eager: true,
requiredVersion: dependencies.react,
},
'react-dom': {
singleton: true,
strictVersion: true,
eager: true,
requiredVersion: dependencies['react-dom'],
},
...deps, // coming from a script outside
},
}),
),
};
},
};
in my host app i can then target
${process.env.REMOTE_URL}/static/chunks/remotes.js.
I stil have some issues going on but it seems linked to my remote and its dependencies.
I hope it helps a bit !

Auto-import vue reactivity system in vitest for testing composables in Nuxt 3 and vitest

I am using some utils in Nuxt 3. The vue reactivity system (ref, computed, ...) is also imported directly. However, it is not the case for the tests.
Running the spec file importing a ./useBusinessValidation composable throws the error ReferenceError: ref is not defined
Source file ./useBusinessValidation:
import { MaybeRef } from "#vueuse/core"
export const useBusinessValidation = <T>(rule: (payload: T) => true | string, payload: MaybeRef<T>) => {
const validation = computed(() => rule(unref(payload)))
const isValid = computed(() => validation.value === true)
const errorMessage = computed(() => isValid.value ? undefined : validation.value as string)
return {
isValid,
errorMessage
}
}
Spec file useBusinessValidation.spec.ts:
import { useBusinessValidation } from "./useBusinessValidation"
describe('useBusinessValidation', async () => {
it('should be valid with payload respecting the rule', () => {
const rule = (x: number) => x > 0 ? true : `invalid ${x} number. Expected ${x} to be greater than 0.`
const { isValid, errorMessage } = useBusinessValidation(rule, 0)
expect(isValid.value).toBe(true)
expect(errorMessage.value).toBe(undefined)
});
})
and the vitest.config.ts
{
resolve: {
alias: {
'~': '.',
'~~': './',
'##': '.',
'##/': './',
'assets': './assets',
'public': './public',
'public/': './public/'
}
},
test: {
globals: true,
setupFiles: './test/setupUnit.ts',
environment: 'jsdom',
deps: { inline: [/#nuxt\/test-utils-edge/] },
exclude: [
'test/**/**.spec.ts',
'**/node_modules/**',
'**/dist/**',
'**/cypress/**',
'**/.{idea,git,cache,output,temp}/**'
]
}
}
I also tried with the #vitejs/plugin-vue as
plugins: [Vue()]
in the vitest config. It didn't work out.
To auto-import in vitest, install the unplugin-auto-import.
Then, in the vitest.config.ts add:
import AutoImport from 'unplugin-auto-import/vite';
export default defineConfig({
...
plugins: [
AutoImport({
imports: [
'vue',
// could add 'vue-router' or 'vitest', whatever else you need.
],
}),
]
});

React-responsive-carousel styles not working

I am trying to add react-responsive-carousel to my NextJS project. When i run npm run dev everything seems to be fine, however my carousel is rendered with no styles.
import { Carousel } from 'react-responsive-carousel';
import 'react-responsive-carousel/lib/styles/carousel.min.css'; // requires loader
const MyCarousel = () => {
return (
<Carousel
autoPlay
interval={2500}
showArrows={true}
>
<div>content</div>
<div>content</div>
<div>content</div>
</Carousel>
)
}
Documentation says that styles need a loader so I configures next.config.js as follows
const withLess = require('#zeit/next-less');
const withCss = require('#zeit/next-css');
const withImage = require('next-images');
const theme = require('./app/styles/antdoverrides');
module.exports = withImage(
withCss({
cssModules: true,
optimizeFonts: false,
...withLess({
lessLoaderOptions: {
javascriptEnabled: true,
importLoaders: 0,
modifyVars: {
...theme,
},
},
cssLoaderOptions: {
importLoaders: 3,
localIdentName: '[local]___[hash:base64:5]',
},
webpack5: false,
webpack: (config, { isServer }) => {
if (isServer) {
const antStyles = /antd\/.*?\/style.*?/;
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;
},
}),
}),
);
still not getting desired result. Any hints appreciated
You need to import your styles in your _app.js file if you don't use the objects. Just in your _app make import of your styles, something like:
import "../styles/globals.css";
Also you need to npm run local or something like this, check your package.json file to run locally your project instead of build

Dynamic Routes Fail to be Generated by using Firebase in Nuxt js

I'd like to build a Nuxt.js App, in this case, I'm using dynamic routes that to be generated by using config.
Well, I got an issue when I was trying to generate my web page using Nuxt & Firebase.
Here are my Nuxt Config JS code :
import * as firebase from 'firebase';
import 'firebase/auth';
import 'firebase/database';
var firebaseConfig = {
apiKey: "AIzaSyAOX6yNHPzWHWd30GnDagwlhgGv9iP8kLs",
authDomain: "musthofa-lapor.firebaseapp.com",
databaseURL: "https://musthofa-lapor.firebaseio.com",
projectId: "musthofa-lapor",
storageBucket: "musthofa-lapor.appspot.com",
messagingSenderId: "653288691711",
appId: "1:653288691711:web:e49daf72720bf99dc5f9ca",
measurementId: "G-0KW7CGZHL3"
};
var app = firebase.initializeApp(firebaseConfig);
var dbx = app.database();
export default {
mode: 'universal',
/*
** Headers of the page
*/
head: {
title: process.env.npm_package_name || '',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
],
script:[
{ src:'https://www.gstatic.com/firebasejs/7.2.3/firebase-app.js' },
{ src:'https://www.gstatic.com/firebasejs/7.2.3/firebase-auth.js' },
{ src:'https://www.gstatic.com/firebasejs/7.2.3/firebase-database.js' },
{ src:'https://www.gstatic.com/firebasejs/7.2.3/firebase-storage.js' },
]
},
/*
** Customize the progress-bar color
*/
loading: { color: '#fff' },
/*
** Global CSS
*/
css: [
],
/*
** Plugins to load before mounting the App
*/
plugins: [
],
/*
** Nuxt.js dev-modules
*/
buildModules: [
],
/*
** Nuxt.js modules
*/
modules: [
],
/*
** Build configuration
*/
build: {
/*
** You can extend webpack config here
*/
extend (config, { isDev, isClient }) {
if (isDev && isClient) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
}
},
generate:{
routes(){
return dbx.ref('aspirasi').once("value",function(snap){
snap.forEach(function(snapshot){
var this_val = snapshot.val();
return {
route: '/admin/balas/' + this_val.id
}
})
})
}
}
}
It generated error as follows :
ERROR undefined 06:38:45
TypeError: Cannot read property '_normalized' of undefined
at normalizeLocation (/Volumes/DAKSA-HDD/PROJECTS/PRANANDA/MUSTHOFA LAPOR RAKYAT/PROJECTS/WEBSITE/MAIN/musthofa-web/node_modules/vue-router/dist/vue-router.common.js:1297:12)
at VueRouter.resolve (/Volumes/DAKSA-HDD/PROJECTS/PRANANDA/MUSTHOFA LAPOR RAKYAT/PROJECTS/WEBSITE/MAIN/musthofa-web/node_modules/vue-router/dist/vue-router.common.js:2627:18)
at st (server.js:1:31205)
at async e.default (server.js:1:32623)
Any helps will be appreciated. Thank you so much.
Best Regards
This is caused by returning null or undefined from the routes method, and indeed that is what's happening. There's 2 issues with your code:
You are not returning a value from your callback function.
Using return in a forEach does not return the value to the caller. forEach has a return type of undefined, so you should use map instead.
routes(){
return dbx.ref('aspirasi').once("value",function(snap){
return snap.map(function(snapshot){
var this_val = snapshot.val();
return {
route: '/admin/balas/' + this_val.id
}
})
})
}
Bonus: Your code could be cleaned up a lot by using ES6 syntax and async/await:
async routes() {
const snapshot = await dbx.ref("aspirasi").once("value")
return snapshot.map(snap => ({ route: "/admin/balas/" + snap.val().id }))
}

Resources