NextJS ServerSideProps translation don't work properly in dynamic routes - next.js

Hi everyone I have a NextJS app ( main host ) inside a NX Project.
I have the need to translate the pages inside the app, and i'm using next-i18next package installed.
I have several dynamic pages like:
pages
|- projects
| |- index.js
| |- [id]
| | | - index.js
|
| index.js
| _app.js
And locally everything works just fine, but when I deploy to Vercel the translations inside the dynamic pages don't work.
I really don't understand why it's happening, one solution I've found was to transform all dynamic rendered pages into static ones, but this is not possible since new ids are generated during the usage of the application.
Packages I'm using:
"i18next": "^22.0.6",
"next": "13.0.0",
"next-i18next": "^13.0.0",
Code inside dynamic route:
export async function getServerSideProps({ locale }) {
return {
props: {
...(await ssrTranslations(locale, [
'projects',
'shared',
'newgateway-file',
'gatewaysummary',
])),
},
};
}
Next-i18next.config.js
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'it', 'de', 'es', 'fr', 'ja'],
},
defaultNs: 'shared',
fallbackLng: { default: ['en'] },
localePath: 'apps/host/public/locales'
};
Next.config.js
const { withNx } = require('#nrwl/next/plugins/with-nx');
const { i18n } = require('./next-i18next.config');
/**
* #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,
},
reactStrictMode: true,
swcMinify: true,
i18n,
};
module.exports = withNx(nextConfig);

Related

How can use .mdx folder in Nextjs v13?

next.config.js
/** #type {import('next').NextConfig} */
const withMDX = require('#next/mdx')({
extension: /\.mdx?$/,
options: {
// If you use remark-gfm, you'll need to use next.config.mjs
// as the package is ESM only
// https://github.com/remarkjs/remark-gfm#install
remarkPlugins: [],
rehypePlugins: [],
// If you use `MDXProvider`, uncomment the following line.
providerImportSource: "#mdx-js/react",
},
})
const nextConfig = withMDX ({
reactStrictMode: true,
pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx'],
})
module.exports = nextConfig
/page/read.mdx
this code in next 12 true working.
but , next.config in next 13
/** #type {import('next').NextConfig} */
const withMDX = require('#next/mdx')({
extension: /\.mdx?$/,
options: {
// If you use remark-gfm, you'll need to use next.config.mjs
// as the package is ESM only
// https://github.com/remarkjs/remark-gfm#install
remarkPlugins: [],
rehypePlugins: [],
// If you use `MDXProvider`, uncomment the following line.
providerImportSource: "#mdx-js/react",
},
})
const nextConfig = withMDX ({
reactStrictMode: true,
swcMinify: true,
experimental: {
appDir: true,
},
pageExtensions: ['ts', 'tsx', 'js', 'jsx', 'md', 'mdx'],
})
module.exports = nextConfig
app> page.mdx not working. 404 page.
How can I get mdx extension when creating page in routing under app folder.
I wanted to do the same thing. Earlier, they had mentioned that you'll need to import the .mdx file for it to work under the caveats of using the app directory here: https://beta.nextjs.org/docs/app-directory-roadmap#caveats I guess they are re-working that.
However, you'll need to mark the whole page as a client component, and import it like so:
// directory -> app/page.jsx
"use client";
// mdx file -> app/(articles)/(philosophy)/hello.mdx
import Hello from './(articles)/(philosophy)/hello.mdx';
const Home = () => {
return <Hello />;
};
export default Home;
You'll see your mdx file content now rendered.

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 !

Remove language from URL in Next JS dynamic routes

I have a website in NextJS with next-i18next, and every page must be translated except for the legal pages.
These legal pages are in markdown, and I have dynamic routing enabled thanks to a [legal].js page and the getStaticPaths and getStaticProps in it.
The problem is that by building my website, my legal pages are prefixed with the language (here en). I would like to remove it as I don't want these pages to be translated.
What am I doing wrong here?
Thanks a lot 🙏
Folder structure:
pages
|- index.js
|- [legal].js
|- privacy-policy.mdx
next-i18next.config.js
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en'],
fallbackLng: 'en',
defaultNS: ['homepage', 'header', 'footer'],
localeDetection: false,
},
}
[legal].js
import matter from 'gray-matter'
import ReactMarkdown from 'react-markdown'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import glob from 'glob'
const LegalPage = ({ markdownBody }) => (
<ReactMarkdown>{markdownBody}</ReactMarkdown>
)
export async function getStaticProps({ locale, params }) {
const { legal } = params
const content = await import(`./${legal}.mdx`)
const data = matter(content.default)
return {
props: {
...(await serverSideTranslations(locale, ['header', 'footer'])),
markdownBody: data.content,
},
}
}
export async function getStaticPaths() {
const blogs = glob.sync('src/pages/**/*.mdx')
const blogSlugs = blogs.map(file => {
const parts = file.split('/')
return parts[parts.length - 1].replace('.mdx', '')
})
const paths = blogSlugs.map(slug => ({
params: { legal: slug },
}))
return {
paths,
fallback: false,
}
}
export default LegalPage
build output:
All static HTML files should be created in separate folders for each locale.
Your default locale can be omitted in the URL, and the following URLs are equivalent:
example.com/my-first-blog
example.com/en/my-first-blog
🎈 As a solution, you can setup app i18n base on domain:
module.exports = {
i18n: {
locales: ['en'],
defaultLocale: 'en',
domains: [
{
domain: 'example.com',
defaultLocale: 'en',
},
]
}
}

how to setup antd less support with nextjs 12

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',
});
}

How to setup storybook at root level lerna monorepo

I am working on a project which is set up with lerna mono repo, we have multiple stencilJS projects for an individual component inside packages of monorepo.
My project sructure is:
I am new to the storybook, now I have to set up the storybook at the root level which all the packages storybook.
I followed an article on the internet and I have set up something which works only for a single package component, due to the current style of setup.
Due to defineCUstomElements in preview.js it is loading the first project package loader I am able to see only the first project stories. Css is not loading for second project stories.
Can someone help me to set up a storybook at the root level which works for all packages?
My example
storybook/main.js
module.exports = {
"stories": [
"../stories/**/*.stories.mdx",
"../packages/plugin-*/src/components/plugin-*/*.stories.#(js|jsx|ts|tsx)"
],
"addons": [
'#storybook/addon-links',
'#storybook/addon-essentials',
'#storybook/addon-viewport',
'#storybook/addon-notes',
'#storybook/addon-docs'
]
}
storybook/preview.js
import { defineCustomElements } from '../packages/stencilProj1/loader';;
defineCustomElements();
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
};
package/stencilProj1/component1.stories.ts
import readme from './readme.md'
import React from 'react';
import ComponentButton from '../../../dist/collection/components/ComponentButton /ComponentButton';
export default {
title: 'Button',
component: ComponentButton,
argTypes: {
label: { control: 'text' },
type: { type: 'select', options: ['primary'] },
disabled: { control: 'boolean' }
},
parameters: {
markdown: readme
},
};
const Template = ({ label, type, disabled = false }) => {
return <component-button type={type} disabled={disabled}>{label}</component-button>;
};
export const Primary = Template.bind({});
Primary.args = {
type: 'primary',
label: 'Primary Button',
};
After a couple of months of attempts, I finally solved this puzzle :) And want to share my solution with community
I have a lerna v4 monorepo for react v17 + mui v5 components written in typescript and flavored with storybook v6 and webpack v5
mui has its wrappers in preview.js, that's why I added the path to .storybook in babel-loader
module.exports = {
core: {
builder: "webpack5",
},
framework: "#storybook/react",
stories: ["../components/**/*.stories.#(ts|tsx)"],
addons: [
"#storybook/addon-links",
"#storybook/addon-essentials",
{
name: "#storybook/preset-create-react-app",
options: {
craOverrides: {
fileLoaderExcludes: ["less"],
},
},
},
],
webpackFinal: config => {
const {
module: {
rules: [, , , , , { oneOf }],
},
} = config;
const babelLoader = oneOf.find(({ test }) => new RegExp(test).test(".ts"));
babelLoader.include = [/components\/(.*)\/src/, /.storybook/];
babelLoader.options.sourceType = "unambiguous";
return config;
},
};
it is also worth to mention my tsconfig has these lines
"rootDirs": [
"./src",
],
Have you tried to import project 2's defineCustomElement with "as" to rename it and use it?
(something along the line of following inside preview.js)
import { defineCustomElements } from '../packages/stencilProj1/loader';
import { defineCustomElements as defineSecondProject } from '../packages/stencilProj2/loader';
defineCustomElements();
defineSecondProject();
This is very manual and even if this works, if you have many repo might not be good solution but I've done something similar to load multiple component loaders and that seem to work OK for my use case in the past.

Resources