Closed codeflorist closed 8 months ago
I had had the same issue before, the eslint show the no-undef warning when I use hooks that be auto-imported.
To solve this issue, I try add this code to buildModules below:
// nuxt.config.ts
import { defineNuxtConfig } from 'nuxt3';
// https://v3.nuxtjs.org/docs/directory-structure/nuxt.config
export default defineNuxtConfig({
buildModules: [...otherBuildModules, './modules/auto-import-eslint'],
});
// modules/auto-import-eslint
import { defineNuxtModule, addTemplate } from '@nuxt/kit';
import type { AutoImport } from '@nuxt/schema';
export default defineNuxtModule({
setup(_, nuxt) {
nuxt.hook('autoImports:extend', autoImports => {
generateEslintGlobalsConfig(autoImports);
});
},
});
function generateEslintGlobalsConfig(autoImports: AutoImport[]) {
addTemplate({
filename: '.eslintrc.js',
write: true,
getContents: () => {
return `// Auto generate by nuxt modules
module.exports = {
globals: {
${autoImports.map(i => ` ${i.as}: 'readonly',`).join('\n')}
},
};
`;
},
});
}
It will generate the .eslintrc.js
file on .nuxt/
, and put it into the root of existing project.
// .eslintrc.js
module.exports = {
extends: [
'./.nuxt/.eslintrc.js'
]
}
And run nuxi dev
, eslint will be pass.
But this is not the best solution, because I will not run nuxi dev
on CI pipeline
any updates? @Mini-ghost 's solution is good but its not good for the production.
I had had the same issue before, the eslint show the no-undef warning when I use hooks that be auto-imported.
To solve this issue, I try add this code to buildModules below:
// nuxt.config.ts import { defineNuxtConfig } from 'nuxt3'; // https://v3.nuxtjs.org/docs/directory-structure/nuxt.config export default defineNuxtConfig({ buildModules: [...otherBuildModules, './modules/auto-import-eslint'], });
// modules/auto-import-eslint import { defineNuxtModule, addTemplate } from '@nuxt/kit'; import type { AutoImport } from '@nuxt/schema'; export default defineNuxtModule({ setup(_, nuxt) { nuxt.hook('autoImports:extend', autoImports => { generateEslintGlobalsConfig(autoImports); }); }, }); function generateEslintGlobalsConfig(autoImports: AutoImport[]) { addTemplate({ filename: '.eslintrc.js', write: true, getContents: () => { return `// Auto generate by nuxt modules module.exports = { globals: { ${autoImports.map(i => ` ${i.as}: 'readonly',`).join('\n')} }, }; `; }, }); }
It will generate the
.eslintrc.js
file on.nuxt/
, and put it into the root of existing project.// .eslintrc.js module.exports = { extends: [ './.nuxt/.eslintrc.js' ] }
And run
nuxi dev
, eslint will be pass.But this is not the best solution, because I will not run
nuxi dev
on CI pipeline
For current code (nuxt@3.0.0-rc.4), it seems like it's hook 'autoImports:sources'
instead of hook 'autoImports:extend'
.
(Update: I am still not quite sure about when the hook 'autoImports:extend'
will be called. It looks like that it will be called in the function regenerateAutoImports
.)
Related discussion
I create my own ESLint plugin and provide globals that can be added to the ESLint configuration. I tried to dynamically fetch things that will be automatically imported by default, and then generate a globals list.
I just start trying nuxt3@3.0.0-rc.4
from today, and I am quite new to Nuxt
and this nuxt/eslint-plugin-nuxt
ESLint plugin. Since I am not quite familiar with things like nuxt production environment or the build-time hook, so I create a plugin to solve this problem in my own repository, instead of creating a pull request here.
i'm wondering what is the difference between nuxt/eslint-plugin-nuxt and nuxt/eslint-config. both seem to be actively developed and have a similar scope. and what's their compatibility with nuxt3?
For this question, I found an issue (nuxt/eslint-plugin-nuxt#110) that seems related to it.
For current code (nuxt@3.0.0-rc.4), it seems like it's hook
'autoImports:sources'
instead of hook'autoImports:extend'
.
I just figure out that when the hook 'autoImports:extend'
is called, things like composables will be auto-imported. So I guess we need 'autoImports:sources'
for adding default auto-imported helper functions & Vue API to globals, and also 'autoImports:extend'
for adding things like composables.
For current code (nuxt@3.0.0-rc.4), it seems like it's hook
'autoImports:sources'
instead of hook'autoImports:extend'
.I just figure out that when the hook
'autoImports:extend'
is called, things like composables will be auto-imported. So I guess we need'autoImports:sources'
for adding default auto-imported helper functions & Vue API to globals, and also'autoImports:extend'
for adding things like composables.
How did you test? I couldn't find when 'autoImports:extend'
is called?
Currently, I'm solving this problem with this code. Maybe it helps in your plugin @LuckyWindsck :
import { defineNuxtModule, addTemplate } from '@nuxt/kit'
export default defineNuxtModule({
setup(_, nuxt) {
nuxt.hook('autoImports:sources', (autoImports) => {
generateEslintGlobalsConfig(autoImports)
})
},
})
function generateEslintGlobalsConfig(autoImports: Array<object>) {
addTemplate({
filename: '.eslintrc.js',
write: true,
getContents: () => {
return `// Auto generate by nuxt modules
module.exports = {
globals: {
${autoImports
.map((i: object) =>
i.imports
.map((i: string) => {
return ` ${i}: 'readonly',`
})
.join('\n')
)
.join('\n')}
},
};
`
},
})
}
For current code (nuxt@3.0.0-rc.4), it seems like it's hook
'autoImports:sources'
instead of hook'autoImports:extend'
.I just figure out that when the hook
'autoImports:extend'
is called, things like composables will be auto-imported. So I guess we need'autoImports:sources'
for adding default auto-imported helper functions & Vue API to globals, and also'autoImports:extend'
for adding things like composables.How did you test? I couldn't find when
'autoImports:extend'
is called?
I found that there are currently (v3.0.0-rc.4
) only 3 hooks related to autoImports.
autoImports:sources
This hook is called with options.presets
, which is indeed the defaultPresets
defined in src/auto-imports/presets.ts
.
This defaultPresets
array includes helper functions and Vue APIs.
autoImports:dirs
This hook is called with composablesDirs
. I am not quite sure what nuxt.options._layers
is, but it seems like that it's an array with all the path of directories that includes composable files.
autoImports:extend
This hook is called with imports
. It's the parameter of the callback function of ctx.modifyDynamicImports
. I am not quite sure what the value it is when it is passed to the callback function, but later composablesDirs
is scanned by scanDirExports
, and all composables are auto-imported.
Does this answer your question?
Currently, I'm solving this problem with this code. Maybe it helps in your plugin @LuckyWindsck :
import { defineNuxtModule, addTemplate } from '@nuxt/kit' export default defineNuxtModule({ setup(_, nuxt) { nuxt.hook('autoImports:sources', (autoImports) => { generateEslintGlobalsConfig(autoImports) }) }, }) function generateEslintGlobalsConfig(autoImports: Array<object>) { addTemplate({ filename: '.eslintrc.js', write: true, getContents: () => { return `// Auto generate by nuxt modules module.exports = { globals: { ${autoImports .map((i: object) => i.imports .map((i: string) => { return ` ${i}: 'readonly',` }) .join('\n') ) .join('\n')} }, }; ` }, }) }
Thanks your code. I also use the hook autoImports:sources
to generate global variables in the default presets in my generate-globals.js
. However I couldn't do that for user-defined composables with just an ESLint plugin. So currently I am following the way that @Mini-ghost did before to create my own module.
// ./modules/auto-import-eslint.ts
import { addTemplate, defineNuxtModule } from '@nuxt/kit'
import { basename, resolve } from 'path'
import type { ImportPresetWithDeprecation } from '@nuxt/schema'
import type { Import } from 'unimport'
const autoImportEslint = defineNuxtModule({
setup(_, nuxt) {
const padding = ' '.repeat(4)
let globalsString = ''
nuxt.hook('autoImports:sources', (defaultPresets: ImportPresetWithDeprecation[]) => {
// console.log('autoImports:sources', defaultPresets)
globalsString += defaultPresets.map((preset) => {
const presetGlobals = preset.imports.map((variableName) => `${padding}${variableName}: 'readonly',`).join('\n')
return `${padding}/* ${preset.from} */\n${presetGlobals}`
}).join('\n')
globalsString += '\n'
})
// nuxt.hook('autoImports:dirs', (dirs: string[]) => {
// console.log('autoImports:dirs', dirs)
// })
nuxt.hook('autoImports:extend', (composableImport: Import[]) => {
// console.log('autoImports:extend', composableImport)
globalsString += `${padding}/* composables */\n`
globalsString += composableImport.map((autoImport) => {
const variableName = autoImport.as
return `${padding}${variableName}: 'readonly',`
}).join('\n')
})
nuxt.hook('modules:done', () => {
const outDir = basename(nuxt.options.buildDir)
const filename = '.eslintrc.js'
const fullPath = resolve(outDir, filename)
const getContents = () => {
// To prevent formatter accidentally fix padding of template string
let contents = ''
contents += '// Auto generate by nuxt modules\n'
contents += 'module.exports = {\n'
contents += ' globals: {\n'
contents += `${globalsString}\n`
contents += ' },\n'
contents += '};\n'
return contents
}
// console.log(getContents())
addTemplate({
filename,
getContents,
write: true,
})
console.log(`globals file is generated at ${fullPath}`)
})
},
})
export default autoImportEslint
The hook autoImports:sources
handles defaultPresets
and the hook autoImports:extend
handles user-defined composables. Since I want to merge those globals in to a single file, I use another hook modules:done
to write .nuxt/.eslintrc.js
.
I am still learning Nuxt3, and I am still testing this module while I learn Nuxt3. Maybe I will publish this module later or find an appropriate repository to submit a pull request.
Thanks for the script, here is my version of it that generates a eslintrc.JSON file (I'm using type: module in my project and a js with module.exports is problematic therefore :))
// https://github.com/nuxt/eslint-plugin-nuxt/issues/173
// ./modules/auto-import-eslint.ts
import { basename, resolve } from 'path';
import type { ImportPresetWithDeprecation } from '@nuxt/schema';
import type { Import } from 'unimport';
import { addTemplate, defineNuxtModule } from '@nuxt/kit';
const padding = ' '.repeat(4);
const autoImportEslint = defineNuxtModule({
setup(_, nuxt) {
const autoImports: { [key: string]: string[] } = {};
nuxt.hook('autoImports:sources', (defaultPresets: ImportPresetWithDeprecation[]) => {
defaultPresets.forEach(preset => {
autoImports[preset.from] = preset.imports.map(p => p.toString());
});
});
nuxt.hook('autoImports:extend', (composableImport: Import[]) => {
autoImports.composables = composableImport.map(autoImport => autoImport.as!.toString());
});
nuxt.hook('modules:done', () => {
console.log('autoImports', autoImports);
const outDir = basename(nuxt.options.buildDir);
const filename = '.eslintrc.json';
const fullPath = resolve(outDir, filename);
const getContents = () => {
// To prevent formatter accidentally fix padding of template string
let contents = '';
contents += '{\n';
contents += ' "globals": {';
for (const autoImport in autoImports) {
contents += `\n${padding}// ${autoImport}`;
autoImports[autoImport].forEach(imp => {
contents += '\n';
contents += `${padding}"${imp}": "readonly",`;
});
}
contents = `${contents.slice(0, -1)}\n`;
contents += ' }\n';
contents += '}\n';
return contents;
};
addTemplate({
filename,
getContents,
write: true
});
console.log(`globals file is generated at ${fullPath}`);
});
}
});
export default autoImportEslint;
Thanks for the script, here is my version of it that generates a eslintrc.JSON file (I'm using type: module in my project and a js with module.exports is problematic therefore :))
// https://github.com/nuxt/eslint-plugin-nuxt/issues/173 // ./modules/auto-import-eslint.ts import { basename, resolve } from 'path'; import type { ImportPresetWithDeprecation } from '@nuxt/schema'; import type { Import } from 'unimport'; import { addTemplate, defineNuxtModule } from '@nuxt/kit'; const padding = ' '.repeat(4); const autoImportEslint = defineNuxtModule({ setup(_, nuxt) { const autoImports: { [key: string]: string[] } = {}; nuxt.hook('autoImports:sources', (defaultPresets: ImportPresetWithDeprecation[]) => { defaultPresets.forEach(preset => { autoImports[preset.from] = preset.imports.map(p => p.toString()); }); }); nuxt.hook('autoImports:extend', (composableImport: Import[]) => { autoImports.composables = composableImport.map(autoImport => autoImport.as!.toString()); }); nuxt.hook('modules:done', () => { console.log('autoImports', autoImports); const outDir = basename(nuxt.options.buildDir); const filename = '.eslintrc.json'; const fullPath = resolve(outDir, filename); const getContents = () => { // To prevent formatter accidentally fix padding of template string let contents = ''; contents += '{\n'; contents += ' "globals": {'; for (const autoImport in autoImports) { contents += `\n${padding}// ${autoImport}`; autoImports[autoImport].forEach(imp => { contents += '\n'; contents += `${padding}"${imp}": "readonly",`; }); } contents = `${contents.slice(0, -1)}\n`; contents += ' }\n'; contents += '}\n'; return contents; }; addTemplate({ filename, getContents, write: true }); console.log(`globals file is generated at ${fullPath}`); }); } }); export default autoImportEslint;
Not working on "nuxt": "^3.0.0-rc.5",
. The error on below:
ERROR Cannot start nuxt: Cannot read properties of undefined (reading 'toString')
at modules/auto-import-eslint.ts:26:21
at Array.map (<anonymous>)
at modules/auto-import-eslint.ts:25:50
at node_modules/hookable/dist/index.mjs:39:70
at async node_modules/nuxt/dist/index.mjs:1009:9
at async Object.modifyDynamicImports (node_modules/unimport/dist/chunks/context.mjs:629:20)
at async regenerateAutoImports (node_modules/nuxt/dist/index.mjs:1007:7)
at async setup (node_modules/nuxt/dist/index.mjs:1012:5)
at async Object.normalizedModule (node_modules/@nuxt/kit/dist/index.mjs:607:5)
at async installModule (node_modules/@nuxt/kit/dist/index.mjs:432:3)
Thanks for the script, here is my version of it that generates a eslintrc.JSON file (I'm using type: module in my project and a js with module.exports is problematic therefore :))
// https://github.com/nuxt/eslint-plugin-nuxt/issues/173 // ./modules/auto-import-eslint.ts import { basename, resolve } from 'path'; import type { ImportPresetWithDeprecation } from '@nuxt/schema'; import type { Import } from 'unimport'; import { addTemplate, defineNuxtModule } from '@nuxt/kit'; const padding = ' '.repeat(4); const autoImportEslint = defineNuxtModule({ setup(_, nuxt) { const autoImports: { [key: string]: string[] } = {}; nuxt.hook('autoImports:sources', (defaultPresets: ImportPresetWithDeprecation[]) => { defaultPresets.forEach(preset => { autoImports[preset.from] = preset.imports.map(p => p.toString()); }); }); nuxt.hook('autoImports:extend', (composableImport: Import[]) => { autoImports.composables = composableImport.map(autoImport => autoImport.as!.toString()); }); nuxt.hook('modules:done', () => { console.log('autoImports', autoImports); const outDir = basename(nuxt.options.buildDir); const filename = '.eslintrc.json'; const fullPath = resolve(outDir, filename); const getContents = () => { // To prevent formatter accidentally fix padding of template string let contents = ''; contents += '{\n'; contents += ' "globals": {'; for (const autoImport in autoImports) { contents += `\n${padding}// ${autoImport}`; autoImports[autoImport].forEach(imp => { contents += '\n'; contents += `${padding}"${imp}": "readonly",`; }); } contents = `${contents.slice(0, -1)}\n`; contents += ' }\n'; contents += '}\n'; return contents; }; addTemplate({ filename, getContents, write: true }); console.log(`globals file is generated at ${fullPath}`); }); } }); export default autoImportEslint;
Not working on
"nuxt": "^3.0.0-rc.5",
. The error on below:ERROR Cannot start nuxt: Cannot read properties of undefined (reading 'toString') at modules/auto-import-eslint.ts:26:21 at Array.map (<anonymous>) at modules/auto-import-eslint.ts:25:50 at node_modules/hookable/dist/index.mjs:39:70 at async node_modules/nuxt/dist/index.mjs:1009:9 at async Object.modifyDynamicImports (node_modules/unimport/dist/chunks/context.mjs:629:20) at async regenerateAutoImports (node_modules/nuxt/dist/index.mjs:1007:7) at async setup (node_modules/nuxt/dist/index.mjs:1012:5) at async Object.normalizedModule (node_modules/@nuxt/kit/dist/index.mjs:607:5) at async installModule (node_modules/@nuxt/kit/dist/index.mjs:432:3)
I solved this issue. This problem happening because of some package composables don't have as
key. It didn't work on me beacuse Pinia (usePinia
) don't have as
key in its composable. So i added condition for it:
nuxt.hook('autoImports:extend', (composableImport: Import[]) => {
autoImports.composables = composableImport.map((autoImport) => {
if (autoImport.as) return autoImport.as!.toString()
return autoImport.name.toString()
})
})
It works well in "nuxt": "^3.0.0-rc.5"
.
Any news on the issue?
I guess this plugin is abandoned since it hasn't been updated in almost a year and https://github.com/nuxt/eslint-config is the way to go for Nuxt 3..?
For nuxt 3.4.2
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
// ...some modules,
'./modules/auto-import-eslint.ts'
]
})
// modules/auto-import-eslint.ts
import { basename, resolve } from 'path'
import type { Import, Unimport } from 'unimport'
import { addTemplate, defineNuxtModule } from '@nuxt/kit'
const padding = ' '.repeat(4)
const autoImportEslint = defineNuxtModule({
setup (_, nuxt) {
// console.log('autoImportEslint', _)
const autoImports: { [key: string]: string[] } = {
// global imports
global: [
'$fetch',
'useCloneDeep',
'defineNuxtConfig',
'definePageMeta',
'defineI18nConfig'
]
}
nuxt.hook('imports:context', async (context: Unimport) => {
const imports = await context.getImports()
imports.forEach(autoImport => {
const list = autoImports[autoImport.from] || []
const name = autoImport.as ? autoImport.as!.toString() : autoImport.name.toString()
autoImports[autoImport.from] = list.concat([name])
})
})
nuxt.hook('imports:extend', (composableImport: Import[]) => {
// console.log('imports:extend', composableImport)
autoImports.composables = composableImport.map(autoImport => {
if (autoImport.as) return autoImport.as!.toString()
return autoImport.name.toString()
})
})
nuxt.hook('modules:done', () => {
// console.log('autoImports', autoImports)
const outDir = basename(nuxt.options.buildDir)
const filename = '.eslint.gloabls.json'
const fullPath = resolve(outDir, filename)
const getContents = () => {
// To prevent formatter accidentally fix padding of template string
let contents = ''
contents += '{\n'
contents += ' "globals": {'
for (const autoImport in autoImports) {
contents += `\n${padding}// ${autoImport}`
autoImports[autoImport].forEach(imp => {
contents += '\n'
contents += `${padding}"${imp}": "readonly",`
})
}
contents = `${contents.slice(0, -1)}\n`
contents += ' }\n'
contents += '}\n'
return contents
}
addTemplate({
filename,
getContents,
write: true
})
console.log(`globals file is generated at ${fullPath}`)
})
}
})
export default autoImportEslint
.eslintrc.json
{
"extends": [
"./.nuxt/.eslint.gloabls.json"
]
}
For nuxt 3.4.2
// nuxt.config.ts export default defineNuxtConfig({ modules: [ // ...some modules, './modules/auto-import-eslint.ts' ] })
// modules/auto-import-eslint.ts import { basename, resolve } from 'path' import type { Import, Unimport } from 'unimport' import { addTemplate, defineNuxtModule } from '@nuxt/kit' const padding = ' '.repeat(4) const autoImportEslint = defineNuxtModule({ setup (_, nuxt) { // console.log('autoImportEslint', _) const autoImports: { [key: string]: string[] } = { // global imports global: [ '$fetch', 'useCloneDeep', 'defineNuxtConfig', 'definePageMeta', 'defineI18nConfig' ] } nuxt.hook('imports:context', async (context: Unimport) => { const imports = await context.getImports() imports.forEach(autoImport => { const list = autoImports[autoImport.from] || [] const name = autoImport.as ? autoImport.as!.toString() : autoImport.name.toString() autoImports[autoImport.from] = list.concat([name]) }) }) nuxt.hook('imports:extend', (composableImport: Import[]) => { // console.log('imports:extend', composableImport) autoImports.composables = composableImport.map(autoImport => { if (autoImport.as) return autoImport.as!.toString() return autoImport.name.toString() }) }) nuxt.hook('modules:done', () => { // console.log('autoImports', autoImports) const outDir = basename(nuxt.options.buildDir) const filename = '.eslint.gloabls.json' const fullPath = resolve(outDir, filename) const getContents = () => { // To prevent formatter accidentally fix padding of template string let contents = '' contents += '{\n' contents += ' "globals": {' for (const autoImport in autoImports) { contents += `\n${padding}// ${autoImport}` autoImports[autoImport].forEach(imp => { contents += '\n' contents += `${padding}"${imp}": "readonly",` }) } contents = `${contents.slice(0, -1)}\n` contents += ' }\n' contents += '}\n' return contents } addTemplate({ filename, getContents, write: true }) console.log(`globals file is generated at ${fullPath}`) }) } }) export default autoImportEslint
extend to
.eslintrc.json
{ "extends": [ "./.nuxt/.eslint.gloabls.json" ] }
This does not seem to work for my project. How did you add eslint to your project?
I used the ESLint module for Nuxt 3.
And my nuxt config and eslintrc.json looks like the following:
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
// ...some modules,
'@nuxtjs/eslint-module',
'./modules/auto-import-eslint.ts'
]
})
// .eslintrc.json
{
"extends": [
"./.nuxt/.eslint.gloabls.json"
]
}
I also added your auto-import-eslint.ts
to the modules
directory.
Link to the ESLint module for Nuxt 3: https://nuxt.com/modules/eslint
I got a response from Daniel Roe in Discord regarding the future of this repo https://discord.com/channels/473401852243869706/897487139888062506/1129384355433812039
So, for now it is recommended to use the nuxt/eslint-config
config only for Nuxt 3 projects. Once this moves to the config repo and integrated, I believe then we should be able to use the plugin again.
Well, at least that's what I will be doing!
I installed @nuxt/eslint-config
and I am trying to run a nuxt-brige / nuxt v2.17 project. This resolved my problem with eslint complaining like useRouter' is not defined no-undef
.
But now I have an error like
Failed to load plugin '@typescript-eslint' declared in '.eslintrc.js » @nuxt/eslint-config': Cannot find module './batchedSingleLineTests'
Is this still the correct way to go? If I downgrade to eslint v7
from v8
I still see the error in the terminal, but at least the frontend runs. Or what would you suggest for the above mentioned setting?
I create my own ESLint plugin and provide globals that can be added to the ESLint configuration. I tried to dynamically fetch things that will be automatically imported by default, and then generate a globals list.
I just start trying
nuxt3@3.0.0-rc.4
from today, and I am quite new toNuxt
and thisnuxt/eslint-plugin-nuxt
ESLint plugin. Since I am not quite familiar with things like nuxt production environment or the build-time hook, so I create a plugin to solve this problem in my own repository, instead of creating a pull request here.
Nice, I forked your repo to add nuxt seo support 🚀 it works pretty well, thanks
https://github.com/Alejandroacho/eslint-plugin-nuxt3-auto-import
For me the issue just ended up being the order of my extends
array; it included something else after it that overwrote something from @nuxt/eslint-config
.
https://github.com/nuxt/eslint with https://github.com/nuxt/eslint/pull/336 should fix it for Nuxt 3.
hi there!
i'm wondering what is the difference between
nuxt/eslint-plugin-nuxt
andnuxt/eslint-config
. both seem to be actively developed and have a similar scope. and what's their compatibility with nuxt3?and would adding of nuxt3's auto-imported globals make sense to add to either of the packages? they currently produce errors with eslint (e.g.
'useRouter' is not defined no-undef
).the current list of globals (as in
.nuxt/auto-imports.d.ts
) seem to be: