diff --git a/distributions/nuxt/package.json b/distributions/nuxt/package.json index 074bf2c13a..9d7a329f39 100644 --- a/distributions/nuxt/package.json +++ b/distributions/nuxt/package.json @@ -51,7 +51,8 @@ "bin": "bin/nuxt.js", "files": [ "bin", - "dist" + "dist", + "webpack.config.js" ], "scripts": { "postinstall": "opencollective || exit 0" diff --git a/distributions/nuxt/src/index.js b/distributions/nuxt/src/index.js index 3d17ff7a2d..c64dc00e73 100644 --- a/distributions/nuxt/src/index.js +++ b/distributions/nuxt/src/index.js @@ -1,3 +1,4 @@ export * from '@nuxt/core' export * from '@nuxt/builder' export * from '@nuxt/generator' +export { getWebpackConfig } from '@nuxt/cli' diff --git a/distributions/nuxt/webpack.config.js b/distributions/nuxt/webpack.config.js new file mode 100644 index 0000000000..a799facfa1 --- /dev/null +++ b/distributions/nuxt/webpack.config.js @@ -0,0 +1,4 @@ +module.exports = function () { + const { getWebpackConfig } = require('.') + return getWebpackConfig() +} diff --git a/packages/cli/src/command.js b/packages/cli/src/command.js index 03a50c8a54..0e4103d71d 100644 --- a/packages/cli/src/command.js +++ b/packages/cli/src/command.js @@ -53,7 +53,7 @@ export default class NuxtCommand extends Hookable { } if (typeof this.cmd.run !== 'function') { - return + throw new TypeError('Invalid command! Commands should at least implement run() function.') } let cmdError diff --git a/packages/cli/src/commands/index.js b/packages/cli/src/commands/index.js index f07ee89926..defb960b05 100644 --- a/packages/cli/src/commands/index.js +++ b/packages/cli/src/commands/index.js @@ -3,6 +3,7 @@ const commands = { dev: () => import('./dev'), build: () => import('./build'), generate: () => import('./generate'), + webpack: () => import('./webpack'), help: () => import('./help') } diff --git a/packages/cli/src/commands/webpack.js b/packages/cli/src/commands/webpack.js new file mode 100644 index 0000000000..5d453f3308 --- /dev/null +++ b/packages/cli/src/commands/webpack.js @@ -0,0 +1,114 @@ +import util from 'util' +import consola from 'consola' +import get from 'lodash/get' +import { common } from '../options' + +export default { + name: 'webpack', + description: 'Inspect Nuxt webpack config', + usage: 'webpack [query...]', + options: { + ...common, + name: { + alias: 'n', + type: 'string', + default: 'client', + description: 'Webpack bundle name: server, client, modern' + }, + depth: { + alias: 'd', + type: 'string', + default: 2, + description: 'Inspection depth' + }, + colors: { + type: 'boolean', + default: process.stdout.isTTY, + description: 'Output with ANSI colors' + }, + dev: { + type: 'boolean', + default: false, + description: 'Inspect development mode webpack config' + } + }, + async run (cmd) { + const { name } = cmd.argv + const queries = [...cmd.argv._] + + const config = await cmd.getNuxtConfig({ dev: cmd.argv.dev, server: false }) + const nuxt = await cmd.getNuxt(config) + const builder = await cmd.getBuilder(nuxt) + const { bundleBuilder } = builder + const webpackConfig = bundleBuilder.getWebpackConfig(name) + + let queryError + const match = queries.reduce((result, query) => { + const m = advancedGet(result, query) + if (m === undefined) { + queryError = query + return result + } + return m + }, webpackConfig) + + const serialized = formatObj(match, { + depth: parseInt(cmd.argv.depth), + colors: cmd.argv.colors + }) + + consola.log(serialized + '\n') + + if (serialized.includes('[Object]' || serialized.includes('[Array'))) { + consola.info('You can use `--depth` or add more queries to inspect `[Object]` and `[Array]` fields.') + } + + if (queryError) { + consola.warn(`No match in webpack config for \`${queryError}\``) + } + } +} + +function advancedGet (obj = {}, query = '') { + let result = obj + + if (!query || !result) { + return result + } + + const [l, r] = query.split('=') + + if (!Array.isArray(result)) { + return typeof result === 'object' ? get(result, l) : result + } + + result = result.filter((i) => { + const v = get(i, l) + + if (!v) { + return + } + + if ( + (v === r) || + (typeof v.test === 'function' && v.test(r)) || + (typeof v.match === 'function' && v.match(r)) || + (r && r.match(v)) + ) { + return true + } + }) + + if (result.length === 1) { + return result[0] + } + + return result.length ? result : undefined +} + +function formatObj (obj, formatOptions) { + if (!util.formatWithOptions) { + return util.format(obj) + } + return util.formatWithOptions(formatOptions, obj) +} diff --git a/packages/cli/src/index.js b/packages/cli/src/index.js index 095d5b402d..fd633598a3 100644 --- a/packages/cli/src/index.js +++ b/packages/cli/src/index.js @@ -12,3 +12,4 @@ export { default as NuxtCommand } from './command' export { default as setup } from './setup' export { default as run } from './run' export { loadNuxtConfig } from './utils/config' +export { getWebpackConfig } from './utils/webpack' diff --git a/packages/cli/src/utils/webpack.js b/packages/cli/src/utils/webpack.js new file mode 100644 index 0000000000..432172efb4 --- /dev/null +++ b/packages/cli/src/utils/webpack.js @@ -0,0 +1,11 @@ +import { core as importCore, builder as importBuilder } from '../imports' + +export async function getWebpackConfig (name = 'client', loadOptions = {}) { + const { loadNuxt } = await importCore() + const { getBuilder } = await importBuilder() + + const nuxt = await loadNuxt(loadOptions) + const builder = await getBuilder(nuxt) + const { bundleBuilder } = builder + return bundleBuilder.getWebpackConfig(name) +} diff --git a/packages/cli/test/unit/__snapshots__/webpack.test.js.snap b/packages/cli/test/unit/__snapshots__/webpack.test.js.snap new file mode 100644 index 0000000000..9017380c9f --- /dev/null +++ b/packages/cli/test/unit/__snapshots__/webpack.test.js.snap @@ -0,0 +1,685 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`webpack getWebpackConfig() 1`] = ` +"Object { + \\"loader\\": \\"vue-loader\\", + \\"options\\": Object { + \\"productionMode\\": true, + \\"transformAssetUrls\\": Object { + \\"embed\\": \\"src\\", + \\"object\\": \\"src\\", + \\"source\\": \\"src\\", + \\"video\\": \\"src\\", + }, + }, + \\"test\\": /\\\\.vue$/i, +}" +`; + +exports[`webpack nuxt webpack devtool 1`] = ` +"false +" +`; + +exports[`webpack nuxt webpack module.rules 1`] = ` +"Array [ + Object { + \\"loader\\": \\"vue-loader\\", + \\"options\\": Object { + \\"productionMode\\": true, + \\"transformAssetUrls\\": Object { + \\"embed\\": \\"src\\", + \\"object\\": \\"src\\", + \\"source\\": \\"src\\", + \\"video\\": \\"src\\", + }, + }, + \\"test\\": /\\\\.vue$/i, + }, + Object { + \\"oneOf\\": Array [ + Object { + \\"resourceQuery\\": /^\\\\?vue/i, + \\"use\\": Array [ + Object { + \\"loader\\": \\"pug-plain-loader\\", + \\"options\\": Object {}, + }, + ], + }, + Object { + \\"use\\": Array [ + \\"raw-loader\\", + Object { + \\"loader\\": \\"pug-plain-loader\\", + \\"options\\": Object {}, + }, + ], + }, + ], + \\"test\\": /\\\\.pug$/i, + }, + Object { + \\"exclude\\": [Function exclude], + \\"test\\": /\\\\.jsx?$/i, + \\"use\\": Array [ + Object { + \\"loader\\": \\"/node_modules/babel-loader/lib/index.js\\", + \\"options\\": Object { + \\"babelrc\\": false, + \\"cacheDirectory\\": false, + \\"configFile\\": false, + \\"envName\\": \\"client\\", + \\"presets\\": Array [ + Array [ + \\"/packages/babel-preset-app/src/index.js\\", + Object {}, + ], + ], + }, + }, + ], + }, + Object { + \\"oneOf\\": Array [ + Object { + \\"resourceQuery\\": /module/, + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"modules\\": Object { + \\"localIdentName\\": \\"[local]_[hash:base64:5]\\", + }, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + ], + }, + Object { + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + ], + }, + ], + \\"test\\": /\\\\.css$/i, + }, + Object { + \\"oneOf\\": Array [ + Object { + \\"resourceQuery\\": /module/, + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"modules\\": Object { + \\"localIdentName\\": \\"[local]_[hash:base64:5]\\", + }, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + ], + }, + Object { + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + ], + }, + ], + \\"test\\": /\\\\.p(ost)?css$/i, + }, + Object { + \\"oneOf\\": Array [ + Object { + \\"resourceQuery\\": /module/, + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"modules\\": Object { + \\"localIdentName\\": \\"[local]_[hash:base64:5]\\", + }, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"less-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + ], + }, + Object { + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"less-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + ], + }, + ], + \\"test\\": /\\\\.less$/i, + }, + Object { + \\"oneOf\\": Array [ + Object { + \\"resourceQuery\\": /module/, + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"modules\\": Object { + \\"localIdentName\\": \\"[local]_[hash:base64:5]\\", + }, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"sass-loader\\", + \\"options\\": Object { + \\"sassOptions\\": Object { + \\"indentedSyntax\\": true, + }, + \\"sourceMap\\": false, + }, + }, + ], + }, + Object { + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"sass-loader\\", + \\"options\\": Object { + \\"sassOptions\\": Object { + \\"indentedSyntax\\": true, + }, + \\"sourceMap\\": false, + }, + }, + ], + }, + ], + \\"test\\": /\\\\.sass$/i, + }, + Object { + \\"oneOf\\": Array [ + Object { + \\"resourceQuery\\": /module/, + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"modules\\": Object { + \\"localIdentName\\": \\"[local]_[hash:base64:5]\\", + }, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"sass-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + ], + }, + Object { + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"sass-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + ], + }, + ], + \\"test\\": /\\\\.scss$/i, + }, + Object { + \\"oneOf\\": Array [ + Object { + \\"resourceQuery\\": /module/, + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"modules\\": Object { + \\"localIdentName\\": \\"[local]_[hash:base64:5]\\", + }, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"stylus-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + ], + }, + Object { + \\"use\\": Array [ + Object { + \\"loader\\": \\"vue-style-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"css-loader\\", + \\"options\\": Object { + \\"importLoaders\\": 2, + \\"onlyLocals\\": false, + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"postcss-loader\\", + \\"options\\": Object { + \\"order\\": \\"presetEnvAndCssnanoLast\\", + \\"plugins\\": Array [ + [Function anonymous], + [Function anonymous], + [Function anonymous], + [Function anonymous], + ], + \\"sourceMap\\": false, + }, + }, + Object { + \\"loader\\": \\"stylus-loader\\", + \\"options\\": Object { + \\"sourceMap\\": false, + }, + }, + ], + }, + ], + \\"test\\": /\\\\.styl(us)?$/i, + }, + Object { + \\"test\\": /\\\\.(png|jpe?g|gif|svg|webp)$/i, + \\"use\\": Array [ + Object { + \\"loader\\": \\"url-loader\\", + \\"options\\": Object { + \\"limit\\": 1000, + \\"name\\": \\"img/[contenthash:7].[ext]\\", + }, + }, + ], + }, + Object { + \\"test\\": /\\\\.(woff2?|eot|ttf|otf)(\\\\?.*)?$/i, + \\"use\\": Array [ + Object { + \\"loader\\": \\"url-loader\\", + \\"options\\": Object { + \\"limit\\": 1000, + \\"name\\": \\"fonts/[contenthash:7].[ext]\\", + }, + }, + ], + }, + Object { + \\"test\\": /\\\\.(webm|mp4|ogv)$/i, + \\"use\\": Array [ + Object { + \\"loader\\": \\"file-loader\\", + \\"options\\": Object { + \\"name\\": \\"videos/[contenthash:7].[ext]\\", + }, + }, + ], + }, +] +" +`; + +exports[`webpack nuxt webpack module.rules loader=.*-loader 1`] = ` +"Object { + \\"loader\\": \\"vue-loader\\", + \\"options\\": Object { + \\"productionMode\\": true, + \\"transformAssetUrls\\": Object { + \\"embed\\": \\"src\\", + \\"object\\": \\"src\\", + \\"source\\": \\"src\\", + \\"video\\": \\"src\\", + }, + }, + \\"test\\": /\\\\.vue$/i, +} +" +`; + +exports[`webpack nuxt webpack module.rules loader=vue- 1`] = ` +"Object { + \\"loader\\": \\"vue-loader\\", + \\"options\\": Object { + \\"productionMode\\": true, + \\"transformAssetUrls\\": Object { + \\"embed\\": \\"src\\", + \\"object\\": \\"src\\", + \\"source\\": \\"src\\", + \\"video\\": \\"src\\", + }, + }, + \\"test\\": /\\\\.vue$/i, +} +" +`; + +exports[`webpack nuxt webpack module.rules test=.jsx 1`] = ` +"Object { + \\"exclude\\": [Function exclude], + \\"test\\": /\\\\.jsx?$/i, + \\"use\\": Array [ + Object { + \\"loader\\": \\"/node_modules/babel-loader/lib/index.js\\", + \\"options\\": Object { + \\"babelrc\\": false, + \\"cacheDirectory\\": false, + \\"configFile\\": false, + \\"envName\\": \\"client\\", + \\"presets\\": Array [ + Array [ + \\"/packages/babel-preset-app/src/index.js\\", + Object {}, + ], + ], + }, + }, + ], +} +" +`; + +exports[`webpack nuxt webpack nuxt webpack module rules test=.pug oneOf use.0=raw 1`] = ` +"Object { + \\"use\\": Array [ + \\"raw-loader\\", + Object { + \\"loader\\": \\"pug-plain-loader\\", + \\"options\\": Object {}, + }, + ], +} +" +`; + +exports[`webpack nuxt webpack resolve alias 1`] = ` +"Object { + \\"@\\": \\"/resolve\\", + \\"@@\\": \\"/resolve\\", + \\"assets\\": \\"/resolve/assets\\", + \\"static\\": \\"/resolve/static\\", + \\"vue-meta\\": \\"/node_modules/vue-meta/dist/vue-meta.esm.browser.js\\", + \\"~\\": \\"/resolve\\", + \\"~~\\": \\"/resolve\\", +} +" +`; diff --git a/packages/cli/test/unit/cli.test.js b/packages/cli/test/unit/cli.test.js index 6a192bb8bd..010a475b97 100644 --- a/packages/cli/test/unit/cli.test.js +++ b/packages/cli/test/unit/cli.test.js @@ -26,7 +26,7 @@ describe('cli', () => { const nodeEnv = process.env.NODE_ENV process.env.NODE_ENV = '' - getCommand.mockImplementationOnce(() => Promise.resolve({})) + getCommand.mockImplementationOnce(() => Promise.resolve({ run () { } })) await run(['dev']) expect(process.env.NODE_ENV).toBe('development') @@ -37,7 +37,7 @@ describe('cli', () => { const nodeEnv = process.env.NODE_ENV process.env.NODE_ENV = '' - getCommand.mockImplementationOnce(() => Promise.resolve({})) + getCommand.mockImplementationOnce(() => Promise.resolve({ run () { } })) await run(['', '', 'build']) expect(process.env.NODE_ENV).toBe('production') diff --git a/packages/cli/test/unit/webpack.test.js b/packages/cli/test/unit/webpack.test.js new file mode 100644 index 0000000000..daf43dd513 --- /dev/null +++ b/packages/cli/test/unit/webpack.test.js @@ -0,0 +1,50 @@ +import path from 'path' +import util from 'util' +import consola from 'consola' +import prettyFormat from 'pretty-format' +import { NuxtCommand, getWebpackConfig } from '../..' +import webpackCommand from '../../src/commands/webpack' + +const replaceAll = (str, a, b) => str.split(a).join(b) +const nuxtDir = path.join(__dirname, '../../../..') +const maskDir = str => replaceAll(str, nuxtDir, '') + +const tests = [ + 'devtool', + 'resolve alias', + 'module.rules', + 'module.rules test=.jsx', + 'module.rules loader=vue-', + 'module.rules loader=.*-loader', + 'nuxt webpack module rules test=.pug oneOf use.0=raw' +] + +describe('webpack', () => { + beforeAll(() => { + process.stdout.isTTY = false + util.formatWithOptions = (opts, obj) => prettyFormat(obj) + }) + + afterEach(() => { + jest.resetAllMocks() + }) + + test.posix('getWebpackConfig()', async () => { + const webpackConfig = await getWebpackConfig('Client') + expect(maskDir(prettyFormat(webpackConfig.module.rules[0]))).toMatchSnapshot() + }) + + test.posix('nuxt webpack no match', async () => { + const cmd = NuxtCommand.from(webpackCommand, ['module.rules', 'loader=foobar']) + await cmd.run() + expect(maskDir(consola.warn.mock.calls[0][0])).toBe('No match in webpack config for `loader=foobar`') + }) + + for (const testCase of tests) { + test.posix('nuxt webpack ' + testCase, async () => { + const cmd = NuxtCommand.from(webpackCommand, testCase.split(' ')) + await cmd.run() + expect(maskDir(consola.log.mock.calls[0][0])).toMatchSnapshot() + }) + } +}) diff --git a/packages/utils/src/resolve.js b/packages/utils/src/resolve.js index ab54355afe..09972caa83 100644 --- a/packages/utils/src/resolve.js +++ b/packages/utils/src/resolve.js @@ -106,4 +106,6 @@ export function isIndexFileAndFolder (pluginFiles) { return pluginFiles.some(isIndex) } -export const getMainModule = () => require.main +export const getMainModule = () => { + return require.main || (module && module.main) || module +} diff --git a/packages/webpack/src/builder.js b/packages/webpack/src/builder.js index 29978f3af4..e345953989 100644 --- a/packages/webpack/src/builder.js +++ b/packages/webpack/src/builder.js @@ -34,7 +34,7 @@ export class WebpackBundler { } getWebpackConfig (name) { - const Config = WebpackConfigs[name] // eslint-disable-line import/namespace + const Config = WebpackConfigs[name.toLowerCase()] // eslint-disable-line import/namespace if (!Config) { throw new Error(`Unsupported webpack config ${name}`) } diff --git a/packages/webpack/src/config/index.js b/packages/webpack/src/config/index.js index cd45dafbeb..e22da970a9 100644 --- a/packages/webpack/src/config/index.js +++ b/packages/webpack/src/config/index.js @@ -1,3 +1,3 @@ -export { default as Client } from './client' -export { default as Modern } from './modern' -export { default as Server } from './server' +export { default as client } from './client' +export { default as modern } from './modern' +export { default as server } from './server'