There are SSR-related problems with several pages in Next.js project that results in errors on npm run build and prevent the project from being built:
pages/
foo/
bar/
[id].jsx
index.jsx
index.jsx
...
For example, bar:
export function getStaticProps() {
return someApiCallThatCurrentlyFails()
...
}
export default function Bar() {...}
As a quick fix, it may be convenient to just not build bar/*.* pages and make routes unavailable.
Can pages be ignored on Next.js build without physically changing or removing page component files in the project?
You can configure the pageExtensions in the next.config.js.
// next.config.js
module.exports = {
pageExtensions: ["page.js"],
}
After configuring this, the only pages with *.page.js will be considered in the below given directory structure.
pages/
├── user
│ └── setting
│ ├── index.js
├── _app.page.js
├── _document.page.js
├── list.page.js
└── theme.ts
Custom file ignores patterns that are not supported yet. You can visit the PR created here, and the solution given here. This is the most satisfactory solution so far.
#Mathilda Here from Nextjs docs: it's necessary for all pages including _app, _document, etc.
https://nextjs.org/docs/api-reference/next.config.js/custom-page-extensions
Changing these values affects all Next.js pages, including the following:
- middleware.js
- pages/_document.js
- pages/_app.js
- pages/api/
For example, if you reconfigure .ts page extensions to .page.ts, you would need to rename pages like _app.page.ts.
Related
When I use Sass files in NextJs, I am getting 'conflicting order' warnigs from mini-css-extract-plugin. The conflict always messes up my stylings on build. You can see the error described in the following link:
https://medium.com/iryl/control-css-imports-order-for-next-js-webpack-based-production-applications-3b69765444fd
This is an article with a solution to this issue but it talks about ordering Sass files for only one page. I'm not sure how to do order when there are multiple pages. How can I tackle the conflicting order issue?
if you are using nextjs 9.3 or higher you can use it like css modules. At least this is how they recommend that you do it.
This is an example.
You can also check the Sass support on the Next.js docs.
-- Update
The best way of do it it's by creating a different scss module for each component. It will look something like this.
Components
├── Header
│ ├── Header.js
│ ├── Header.module.css
├── Footer
│ ├── Footer.js
│ ├── Footer.module.css
├── Nav
│ ├── Nav.js
│ ├── Nav.module.css
The main idea of using css modules it's to prevent you from use a global sheet. this way the css will be optimized on the code splitting by components and you don't have to worry about declaring the same class twice, each css module file will generate a unique class name.
I'm working on a project using css modules, the project isn't done yet but the file structure it's almost the same working with sass, you can give it a look if you want.
https://github.com/edgarlr/portfolio/tree/main/components
There are plenty of questions and tutorials on this topic, but none of them cover all use cases for a chrome extension, because most of them assume there's only one entry point.
Here are the requisites:
Multiple "single page applications":
1) popup.html for the extension pop up page
2) options.html for the options page
3) custom.html this is a custom .html file that the extension can refer to "locally"
Each of these files are entry points for React to manipulate the DOM, but they behave independently of each other.
Non React TypeScript files
They must not be bundled together with any other scripts, and gets compiled to its own JavaScript file, for example a background.ts that compiles to background.js (which is refered to in the manifest.json).
I assume this is doable with TypeScript, React and Webpack but I'm not sure how to approach that.
There is a custom CRA template that exactly fits your needs: complex-browserext-typescript.
Usage:
npx create-react-app my-app --template complex-browserext-typescript
By default it sets up 4 entry points associated with page-like extension components:
popup (src/index.tsx) - extension's popup page, replaces the
default index entry point.
options (src/options.tsx) - extension's options page.
background (src/background.ts) - background script.
content (src/content.ts) - content script.
However there is an option to exclude any of the above components except the popup from compilation as well as add extra HTML page(s).
Also see this article for usage example.
I found a solution but it was not using create-react-app and webpack. It looks like parcel supports multiple entry points out of the box without any configuration.
Assuming a directory structure like this:
├── chrome
│ └── background.ts
├── html
│ ├── custom.html
│ ├── options.html
│ └── popup.html
├── manifest.json
├── package.json
├── react
│ ├── custom.tsx
│ ├── options.tsx
│ └── popup.tsx
With Parcel.js you simply do:
parcel build html/*.html react/*.tsx chrome/*.ts
And it will handle the multiple entry points. I created a repository that contains a template for that approach, it contains a fully runnable example.
I have a React site currently in JavaScript/ES that we are converting to TypeScript (🎉). We use the Container and Presentational breakdown, so each component will have either a Container and a Presentational file, or for simpler components just a Presentational file.
Over the course of a build, we will typically build "static" Presentational screens/components first, get them to pass design QA, and then make them dynamic by adding a Container. That means that the Presentational files are usually built first. Containers are built later, if needed.
Our directory structure looks like this:
components
├── SomeComponent
│ └── index.js
│ └── index.jsx
├── SomeOtherComponent
│ └── index.jsx
^^ Here we have SomeComponent which has Container+Presentational, while SomeOtherComponent has only Presentational.
This structure provides us with several benefits:
Imports are short and not "doubled": import SomeComponent from '../screens/SomeComponent' (not import SomeComponent from '../screens/SomeComponent/SomeComponent')
Imports do not need to change when Containers are eventually added. If only a Presentational .jsx file exists, the import above works. When/if a Container .js file is added, it then takes precedence over the .jsx, so the same import now targets the new file by virtue of it existing. (Webpack resolve.extensions = ['.js', '.jsx'])
No need to rename the presentational component file when a Container is added. This keeps git history nicely intact.
Quick & easy visual identification of which file is Container vs Presentational. Presentational is .jsx because that's where our JSX lives.
We use react/jsx-filename-extension to enforce that JSX should only be in .jsx files. This gives our devs get an eslint warning if they try to write JSX in a .js Container file. This enforces the concept that Containers should do business logic (in JS), while Presentationals should just output "dumb" markup (in JSX).
Works great!
The only caveat, which in my opinion is very minor, is: In order for this to work, in our Containers we import the Presentational like so: import SomeComponent from './index.jsx'. I say this is a caveat simply because it's the only place where we import using a complete file extension. No big deal...
In TypeScript, I'd love to just change those file extension from js/jsx to ts/tsx like so:
components
├── SomeComponent
│ └── index.ts
│ └── index.tsx
├── SomeOtherComponent
│ └── index.tsx
But we have a problem: In TypeScript we cannot use file extensions in an import (to the best of my knowledge). So this breaks our ability to execute the "caveat," and seems to force us to have different filenames for the Containers vs Presentationals. 😭
How does your team solve this dilemma?
I have searched for conventions on how other teams navigate this issue, and have come up empty-handed.
I am open to criticism of any part of our convention here, and I invite discussion. This is a higher-level issue that also affects the lower-level day-to-day of our devs. All ideas are good ideas (except the ones that suck)!
A few ideas:
A) ts-ignore
Use // #ts-ignore above the import SomeComponent from './index.tsx' line to mute the error. This feels like bad practice, but what would be the consequences?
Pros:
Allows use of index.ts and index.tsx to mimic our previous setup
No need to rename presentationals when a container is added
No need to change imports when a container is added
Cons:
Feels like bad practice (🚩)
Have to remember to add it and instruct other devs to add it
Requires we add '#typescript-eslint/ban-ts-ignore': 'off' to our eslint conf, which by extension means eslint will no longer prevent people from using #ts-ignore anywhere they want. 😬
What else might this break? Does it kill intellisense? What other havoc would this wreak?
B) PascalCase Presentationals
components
├── SomeComponent
│ └── index.ts
│ └── SomeComponent.tsx
├── SomeOtherComponent
│ └── index.tsx
Pros:
Seems kindof conventional. Some teams use PascalCase for all component names as convention.
No need to change imports when a container is added.
Cons:
Requires renaming presentational file when container is added (messes with git history).
Not as easy to instantly identify which file is container vs presentational. There's a (small) logical leap that must be taken in your mind: "That one is named after the component and when they are named after a component they are presentational").
The two Container/Presentational files will not always be "next to" eachother in the directory. If another file named index.test.ts or index.stories.tsx or styles.js exists, it might be in-between index.ts and presentational.tsx
C) presentational.tsx
components
├── SomeComponent
│ └── index.ts
│ └── presentational.tsx
├── SomeOtherComponent
│ └── index.tsx
Pros:
No need to change imports when a container is added.
Instantly obvious which file is presentational. (Solves problem with B above)
Cons:
Requires renaming presentational file when container is added (messes with git history).
The two Container/Presentational files will not always be "next to" eachother in the directory. If another file named index.test.ts or index.stories.tsx exists, it will be in-between index.ts and presentational.tsx
D) index.presentational.tsx
components
├── SomeComponent
│ └── index.ts
│ └── index.presentational.tsx
├── SomeOtherComponent
│ └── index.tsx
Pros:
No need to change imports when a container is added.
Instantly obvious which file is presentational. (Solves problem with B above)
The two Container/Presentational files will always be "next to" eachother in the directory. (Solves problem with B & C above)
Cons:
Requires renaming presentational file when container is added (messes with git history).
Long filename (not sure I really care about this)
I am using Gatsby (React) for my project. I am using Atomic design folder structure e.g:
src/components/Organisms/Header
In this folder I like to have:
src/components/Organisms/Header/header.js
src/components/Organisms/Header/header.module.scss
How can I import header.js from within src/components/layout.js like:
import Header from '#components/Organisms/Header'
instead of:
import Header from '#components/Organisms/Header/header'
Update:
I managed to do it by:
adding an index.js file to src/components/Organisms/Header/
and export { default } from './header'; in index.js
But are this best practices?
You have a few options here. With all of these you would import src/components/Header.
1. Flat with no component directory (my preference):
src
└── components
├── Header.js
└── header.module.css
Benefits
Less meaningless nesting
No conflicting/confusing filenames open in your editor (e.g. index)
Easy to follow the imports and exports
Drawbacks
Nowhere for one-off resources and sub-components to go
2. Adjacent component and resources-directory (Ruby-style):
src
└── components
├── Header
│ ├── header.module.css
│ └── logo.png
└── Header.js
Benefits
Resources and sub-components are kept together
No conflicting/confusing filenames open in your editor (e.g. index)
Easy to follow the imports and exports
Drawbacks
The component isn't adjacent to resources, so imports require a ./Header/ prefix
Depending on the sorting, the resources directory may not be listed immediately adjacent to the component
3. With a directory index that exports Header:
src
└── components
└── Header
├── Header.js
├── header.module.css
├── index.js
└── logo.png
Benefits
Component and resources are kept together
Sorting doesn't matter
Drawbacks
Conflicting/confusing filenames open in your editor (e.g. index)
Confusing imports and exports, may cause hard-to-diagnose errors
Extra work for every component
We have developed a React component library for internal use. The library uses webpack to bundle everything into a bundle.js. The library is exposed as an NPM module for use by our applications, which so far has been working great.
Recently we added a Grid component that has some very large external dependencies. Even though a few of our applications won't need this component from the library, we decided to include it in the final bundle. This can make a huge difference in bundle size, so I followed Webpack's code splitting guide to break out the Grid component using a dynamic import. For our applications that have this library installed as an NPM module, the component library bundle now looks like this in node_modules:
├── node_modules/
│ ├── [our component library]/
│ │ ├── Grid.js # Asynchronously loaded Grid component
│ │ ├── bundle.js # Main bundle
│ │ └── ... other files in component library bundle
When building the application (also with Webpack), the Grid component doesn't seem to be getting included as its own file in the final bundle. In fact, it doesn't get included at all:
├── dist/
│ ├── main.js # App bundle
│ ├── vendor.js # Vendor bundle created with CommonChunksPlugin
│ └── ... other files in application bundle but no Grid.js
When trying to load a page in the browser that is using the asynchronously loaded Grid component, Webpack returns the following error:
Error: Loading chunk 0 failed.
at HTMLScriptElement.onScriptComplete (bundle.js:757)
Essentially, this says the Grid component chunk can't be found. What am I doing wrong? Is it even possible to code split a React component library like this?
I used https://webpack.js.org/guides/code-splitting/#dynamic-imports both import() and require.ensure syntax for dynamic imports. Both worked well. Check this project of mine for good example https://github.com/croraf/myboiler.
This project also is an example: https://github.com/croraf/nutrients-calculator. But I complicated dynamic import part a bit. Check https://github.com/croraf/nutrients-calculator/blob/master/frontend/src/App.js and https://github.com/croraf/nutrients-calculator/blob/master/frontend/src/routes/util/DynamicRoute.js files.
We decided to take a different route with this. Instead of including the Grid component with the rest of the components we split if off into its own npm module. I still see a use case for dynamically importing react components in a library but we felt this was a better solution to our problem. With this solution, the only real downside is that the application will now need to add 2 npm modules instead of one if it needs to use the Grid component and our standard component library. Since our application does code splitting by route with webpack + dynamic imports, the Grid code only gets bundled into the route that needs it.
one possible reason is babel transpiled your code from import("..") to require. check transpiled file to confirm this.
if this is the case and you are using preset, you can add this to disable this behavior:
"#babel/preset-env",
{
**"modules": false,**
"targets": {
"esmodules": true
}
}
],