-
Notifications
You must be signed in to change notification settings - Fork 27k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
next.config.ts #5318
Comments
If you want to do something like this it's your own responsibility to compile next.config.ts to next.config.js. We're not planning to transpile next.config.js. |
@virzak Yeah, not without much effort. It will require runtime transpilation w/ You can however, use |
any changes here since nextJs Core is running with typescript? |
Any chance this issue could be reconsidered? It was closed over a year ago and a lot has changed since then, TS support is now part of the core. A specific reason I would like to have The same |
Still the same as #5318 (comment) Compiling it would slow down bootup and make config loading significantly more complex compared to the benefits. |
I believe the main performance problem is production-related. What if |
It's both development and production. Note that this file is a config file and generally shouldn't have anything complex in there. |
It should just build and cache the config like everything else so it doesn't slow bootup performance. Plus, I would be shocked if it was a significant performance impact on bootup compared to the benefits. It's frustrating not being able to use a consistent language throughout my entire project and include the same linting tools or esnext syntax.
Umm, maybe for super simple use cases? I don't know. I work on big complex apps that require a lot of customization and tweaking. Data on this would be interesting. They certainly felt it was worthwhile to transpile One particularly useful tool for modifying configs imperatively like this that loses a lot of benefits without transpiling TS is Ramda. That's my FP toolbelt for everything because it has awesome TS support for dynamic type inference when currying. |
Is supporting a transpiled |
Generating a list of urls to export will be covered by |
You probably already have the following 2 packages installed if you are using typescript with nextjs: Then you can use a function like the one below to require typescript file on the fly: function requireTypescript(path) {
const fileContent = require('fs').readFileSync(path, 'utf8')
const compiled = require('@babel/core').transform(
fileContent,
{
filename: path,
presets: [ '@babel/preset-typescript' ],
},
)
return eval(compiled.code)
} Then use it in your const myModule = requireTypescript('./path/to/mymodule.ts') Note: you will need to inject some path information if your ts file is not in the same folder of |
Note about #5318 (comment)
|
But if you decided to use typescript in your project, didn't you already trade in some performance for type safety? How come the performance impact is not seen as problematic when it happens on every change of a file, but is suddenly so insurmountable when it's once on boot? And If you cache it a bit smart it's not even happening on every boot. If the concern is that people would blame
That would make clear to people which impact the use of which tool has for them. |
@Janpot because it's cached inside Next.js and not with this method. On top of that it affects production boot if you use |
Yes, I agree, not with this method. But if next were to hypothetically implement this feature, I presume it wouldn't be too hard to add cache. Since next.js already has infrastructure to compile and cache typescript. And for production boot it could precompile when running |
I used typescript ever since it's supported in nextjs and was thinking that it could be cool that next.config.js to be next.config.ts. But aside type checking, I never needed config to be a typescript file, so this issue didn't bother me too much. But now I wanted to import a I see the workaround suggested by @lsm here, but this requires some overwhelming customization with babel etc just for this one file?? Either babel, or a separate tsconfig and some script running tsc to emit js, so I could import this helper file as js. Which isn't any better... But then I see that author doesn't want to add support for "just this one file" too, and I'm starting to see some irony. 🤔🤔🤔🤔🤔🤦♂️ P.S. I don't know what I'll do with all this yet, but wanted to at least share my feelings UPD. on a second glance, UPD2. ok, I gave up: I changed this ts helper script to js, and required/imported it where I needed (in next.config.js, and in a page, used it in getStaticProps since it uses |
@jerrygreen Would moving that useful helper as TS into an npm package that publishes as JS have been an option for you? |
I've got the same issue as @jerrygreen. Was considering making the code an npm package, but there's too much that will be project-specific so I'd need to publish a new package for each project. I'll have to give up on this for now and just duplicate some of this code in js. However, a better solution to my use case would be to have the option to run scripts during the build cycle, similar to how Gatsby does it in |
@dpwolfe yeah, I agree with @beppek, this thing appears to be a bit too project specific. In my case I have files in pages folder that start with a date (shorten timestamp), something like |
I am running into eslint errors that need to be suppressed like this
This should be reopened or at least something added to the typescript documentation to mention that this is a known issue. It would add polish to document this upfront or even better allow next.config.ts. |
Just like having I'm having the same use case where I want to run some TypeScript code during build time; e.g. generating a sitemap.json or a search-index.json. |
Is there a way to type the config at least? I looked through the source and couldn't find any interface for the config options |
I found a sample at https://github.com/ant-design/antd-mobile-samples/tree/master/web-ssr-ts, which uses next.config.ts. |
@devinrhode2 Is there any official reference for "@types"? Where does it come from? Googled it but I couldn't find the official documentation. |
Wow, there's actually very good jsdoc support, we can use more than just @type: https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html |
You can convert said .ts utility to jsdoc+js, and then As an example, I did this so that only 1 file in our app repo references |
Thank you for the suggestion. However, converting files from TS back to JS is not really a viable solution for many projects (full migration from JS to TS is a often goal of many codebases). The workaround I used in the past it's to execute these tasks separately via |
I ended up using
for more options it's probably better to create a separate |
Next.js bundles SWC now so it seems to me like it might as well look for a |
Thanks @isaachinman! Building on that, the latest esbuild next.config.ts --bundle --outfile=next.config.js --platform=node --external:./node_modules/* --target=es2020 --minify |
Since my previous comment I now use SWC (no babel) and Next allows Here is the config loading code: next.js/packages/next/server/config.ts Lines 633 to 651 in b579a35
You can use cjs config or mjs config. cjsUse the same approach as my comment and use @swr/register instead. mjsNOTE: Use a shell script to run Something like:
|
As a TypeScript enthusiast, I implemented the
how: // package.json
{
"scripts": {
"build:next-config": "esno ./scripts/nextConfig/buildNextConfig.ts",
"watch:next-config": "esno ./scripts/nextConfig/watchNextConfig.ts",
"predev": "npm run build:next-config",
"dev": "concurrently 'next dev' 'npm run watch:next-config'",
"prebuild": "npm run build:next-config",
"build": "next build && esno ./scripts/generate-sitemap.ts",
},
} // scripts/nextConfig/utils.ts
import chokidar from 'chokidar'
import esbuild from 'esbuild'
export const nextConfigTsPath = `${process.cwd()}/next.config.ts`
export const outputPath = `${process.cwd()}/next.config.mjs`
export function buildNextConfig() {
esbuild.buildSync({
entryPoints: [nextConfigTsPath],
outfile: outputPath,
format: 'esm',
platform: 'node',
target: 'es2020',
})
}
export function watchNextConfig() {
chokidar.watch(nextConfigTsPath).on('change', (event, path) => {
buildNextConfig()
})
}
// scripts/nextConfig/buildNextConfig.ts
import { buildNextConfig } from './utils'
buildNextConfig()
// scripts/nextConfig/watchNextConfig.ts
import { watchNextConfig } from './utils'
watchNextConfig() More details refer to my repo: tailwind-nextjs-typescript-starter-blog |
I'm going to re-open this feature request given that we've been reworking the compiler to be faster which unlocks this feature among others. There will have to be limitations to what can be done though given that |
Unfortunately, I find that next.js not auto-restart on next.config.mjs updated, so maybe |
@timneutkens in what ways could |
I believe the greatest benefit here is that we can have a 100% TS codebase, while sharing code between next.config.ts and things in our That being said, compiling next.config.ts means there's likely other imported TS files that need to be compiled. Likely the shared code will compile very quickly, so if it's compiled twice, once for next.config.ts compilation+read, and again for full TS project compilation, I think that's ok from a performance perspective. |
I don't know who will be implementing this, but if it's easy to secretly/experimentally allow .mjs/.mts (top level await) I can imagine many situations where it'd be very powerful :) |
Entirely depends on what other trade-offs are applied but the clear one to make this work would be "next.config.js is only loaded during compilation ( |
I've tried the babel approach before, but my favorite workaround right now is to simply add a Edit: We even infer our // utils/publicConfig.ts
import getConfig from 'next/config';
import type * as config from '../next.config';
/**
* Infers the type from the `publicRuntime` in `next.config.js`
*/
type PublicConfig = typeof config.publicRuntimeConfig;
const nextConfig = getConfig();
export const publicConfig = nextConfig.publicRuntimeConfig as PublicConfig; |
Small note on having .js but TS checks on it: in TS you often need the |
After embarrassing amount of shameless brute forcing, I managed to hack together a JSDoc based solution to go with I hope this saves at least someone the many hours I'll never be getting back. Please let me know if there's a way to simplify this seemingly over complicated mess. 🙏 Disclaimer: Some pieces of the puzzle might be missing and only the relevant bits are included. package.json {
"dependencies": {
"next": "^12.1.4",
...
},
"devDependencies": {
"@tsconfig/next": "^1.0.2",
"typescript": "^4.5.4",
"webpack": "^5.41.1",
...
}
} tsconfig.json {
"extends": "@tsconfig/next/tsconfig.json",
"compilerOptions": {
"baseUrl": "src",
"paths": {
"*": ["../types/*"],
...
"webpack": ["../node_modules/webpack/types"]
},
...
},
"include": [
"next-env.d.ts",
"types/*.d.ts",
"next.config.js",
"src"
],
"exclude": ["node_modules"]
} types/webpack.d.ts export * from 'webpack'; next.config.js /// @ts-check
const webpack = require('webpack');
/** @type {import('next').NextConfig} nextConfig */
const nextConfig = {
// ...
/** @param {import('webpack').Configuration} config */
webpack(config) {
// ...
return config;
}
};
module.exports = nextConfig; |
@devinrhode2 Have you tried if your I'm curious since I had set ours in a similar fashion and just noticed it had broken at some point between two Next.js and TS upgrades and moving the source files under One of my failed attempts was this disaster. please note the comment within the snippet. /**
* @typedef {import('next').NextConfig} NextConfig
* @typedef {import('webpack').Configuration} WebpackConfig
* @typedef {import('next/dist/server/config-shared').WebpackConfigContext} WebpackConfigContext
* @typedef {(config: WebpackConfig, context: WebpackConfigContext) => any} NextWebpackConfig
*/
/** @type {Omit<NextConfig, 'webpack'>} nextConfig */
const nextConfig = {
/** @type {NextWebpackConfig} */
webpack(config, context) {
// depending on what I tried elsewhere in the configuration, I only got either
// config or context to have the intended type but not at the sime time
}
} Among various other approaches, I tried both specifically including My apologies for spamming the people watching this in hopes of an official TS solution. Personally I just find this type of approach is the best workaround at this point, given it works with fast refresh. I'm hoping someone might still find this useful. |
One thing I will say, is you need to Pick<> certain properties out of the NextConfig type. It really shouldn't be necessary, I personally see it as a bug. If you don't Pick certain properties out of the type, which reflect which properties you have in your config object, you don't get any type errors for unknown properties, like WebPak (i.e. a typo) or doesNotExist: true |
That is a good point. I tried using The downside of using /** @type {Configuration} webpack */
const webpack = { ... };
/** @type {NextConfig} nextConfig */
const nextConfig = {
...webpack
}; It's ridiculous how you stop seeing the simplest solutions while getting frustrated and begin to think the issue is more obscure than what it (very often) actually is! Update 4.6.2022: /** @type {import('next').NextConfig}*/
const nextConfig = {
// ...
/** @param {import('webpack').Configuration} config */
webpack(config) { /*.. */ }
} |
Well, bottom line is I think next should make the type for NextConfig stricter. @timneutkens any idea why it allows unknown keys? |
Just an addition, I'm seeing that many people want Though my case for having that is duplicated is importing pieces of ts code to compose my configuration. Basically I have both Because they must have the exact same configuration, I needed to copy and past my TS config implementation inside my If my codebase were fully in javascript, I could import easily that configuration and having a single source of truth. However because it's TS based, I don't have this option. |
Can I suggest someone create a Discussions thread for this? There’s a fair amount of chatter here but the use case has been made quite clear already, so I’d prefer if this thread is kept to just updates regarding the implementation. |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Feature request
Is it possible to use next.config.ts instead of next.config.js?
Currently none of the typescript examples use typescript in the config file. Is it even possible?
@resir014
The text was updated successfully, but these errors were encountered: