-
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(refactor): Refactor app, improve code and stability
An important fix for the way the loaders were being detected and replaced has been addressed. In this commit we're also introducing: - Logging - More types - New eslint config
- Loading branch information
Showing
10 changed files
with
166 additions
and
147 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,20 @@ | ||
|
||
import chalk from 'chalk' | ||
import semver from 'semver' | ||
|
||
export function requireNuxtVersion (currentVersion?: string, requiredVersion?: string) { | ||
export function requireNuxtVersion(currentVersion?: string, requiredVersion?: string) { | ||
// eslint-disable-next-line @typescript-eslint/no-var-requires | ||
const pkgName = require('../package.json').name | ||
|
||
if (!currentVersion || !requireNuxtVersion) { | ||
if (!currentVersion || !requireNuxtVersion) | ||
return | ||
} | ||
|
||
const _currentVersion = semver.coerce(currentVersion)! | ||
const _requiredVersion = semver.coerce(requiredVersion)! | ||
|
||
if (semver.lt(_currentVersion, _requiredVersion)) { | ||
throw new Error(`\n | ||
${chalk.cyan(pkgName)} is not compatible with your current Nuxt version : ${chalk.yellow('v' + currentVersion)}\n | ||
Required: ${chalk.green('v' + requiredVersion)} or ${chalk.cyan('higher')} | ||
${chalk.cyan(pkgName)} is not compatible with your current Nuxt version : ${chalk.yellow(`v${currentVersion}`)}\n | ||
Required: ${chalk.green(`v${requiredVersion}`)} or ${chalk.cyan('higher')} | ||
`) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export const NAME = 'nuxt-build-optimisations' | ||
export const RISK_PROFILE_SAFE = 'safe' | ||
export const RISK_PROFILE_EXPERIMENTAL = 'experimental' | ||
export const RISK_PROFILE_RISKY = 'risky' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,80 @@ | ||
import type { Module } from '@nuxt/types' | ||
import type { ExtendFunctionContext } from '@nuxt/types/config/module' | ||
import type { Configuration as WebpackConfig } from 'webpack' | ||
import defu from 'defu' | ||
import { Configuration as WebpackConfiguration } from 'webpack' | ||
import type { OptimisationArgs, ModuleOptions } from './types' | ||
import { requireNuxtVersion } from './compatibility' | ||
import speedMeasurePlugin from './tools/speed-measure-plugin' | ||
import { webpackOptimiser, imageOptimiser, esbuildOptimiser, nuxtOptimiser } from './optimisations' | ||
import logger from './logger' | ||
import { NAME } from './constants' | ||
|
||
const buildOptimisationsModule: Module<ModuleOptions> = function () { | ||
const buildOptimisationsModule: Module<ModuleOptions> = async function(moduleOptions) { | ||
const { nuxt } = this | ||
const defaults = { | ||
|
||
requireNuxtVersion(nuxt.constructor.version, '2.10') | ||
|
||
const defaultConfig: ModuleOptions = { | ||
measure: false, | ||
measureMode: 'client', | ||
profile: 'experimental', | ||
esbuildMinifyOptions: { | ||
target: 'es2015' | ||
target: 'es2015', | ||
}, | ||
esbuildLoaderOptions: { | ||
target: 'es2015' | ||
target: 'es2015', | ||
}, | ||
features: { | ||
postcssNoPolyfills: true, | ||
esbuildLoader: true, | ||
esbuildMinifier: true, | ||
imageFileLoader: true, | ||
webpackOptimisations: true, | ||
cacheLoader: true, | ||
hardSourcePlugin: true | ||
} | ||
} as ModuleOptions | ||
const buildOptimisations = { | ||
...defaults, | ||
...nuxt.options.buildOptimisations | ||
} as ModuleOptions | ||
|
||
requireNuxtVersion(nuxt.constructor.version, '2.10') | ||
hardSourcePlugin: true, | ||
parallelPlugin: true, | ||
}, | ||
} | ||
const options: ModuleOptions = defu.arrayFn(moduleOptions, nuxt.options.buildOptimisations, defaultConfig) | ||
|
||
// set measure based on env if the env is set | ||
if (typeof process.env.NUXT_MEASURE !== 'undefined') { | ||
buildOptimisations.measure = process.env.NUXT_MEASURE.toLowerCase() === 'true' | ||
} | ||
if (typeof process.env.NUXT_MEASURE !== 'undefined') | ||
options.measure = process.env.NUXT_MEASURE.toLowerCase() === 'true' | ||
|
||
await nuxt.callHook('buildOptimisations:options', options) | ||
logger.debug('post `buildOptimisations:options` hook options', options) | ||
|
||
nuxt.hook('build:before', () => { | ||
nuxt.hook('build:before', (nuxt: any) => { | ||
const args = { | ||
options: buildOptimisations, | ||
options, | ||
nuxtOptions: nuxt.options, | ||
env: { isDev: nuxt.dev || process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'dev' } | ||
env: { isDev: nuxt.dev || process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'dev' }, | ||
} as OptimisationArgs | ||
// if the user has enabled speed measure plugin and we can | ||
|
||
if (process.env.NODE_ENV !== 'test') | ||
logger.info(`\`${NAME}\` enabled with \`${options.profile}\` profile.`) | ||
|
||
// boot speed measure plugin | ||
speedMeasurePlugin(args, nuxt) | ||
// if profile is false we don't add any optimisations | ||
if (buildOptimisations.profile === false) { | ||
if (options.profile === false) | ||
return | ||
} | ||
if (process.env.NODE_ENV !== 'test') { | ||
console.info(`\`nuxt-build-optimisations\` enabled with \`${buildOptimisations.profile}\` profile.`) | ||
} | ||
// @ts-ignore | ||
|
||
nuxtOptimiser(args) | ||
|
||
this.extendBuild((config: WebpackConfig, env: ExtendFunctionContext) => { | ||
args.env = env | ||
this.extendBuild((config: WebpackConfiguration, ctx: ExtendFunctionContext) => { | ||
args.env = ctx | ||
args.config = config | ||
const extendOptimisers = [ | ||
webpackOptimiser, imageOptimiser, esbuildOptimiser | ||
] | ||
for (const k in extendOptimisers) { | ||
extendOptimisers[k](args) | ||
} | ||
args.logger = logger.withScope(ctx.isModern ? 'modern' : (ctx.isClient ? 'client' : 'server')) | ||
// call all of them | ||
webpackOptimiser(args) | ||
imageOptimiser(args) | ||
esbuildOptimiser(args) | ||
}) | ||
}) | ||
} | ||
|
||
// @ts-ignore | ||
buildOptimisationsModule.meta = { name: 'nuxt-build-optimisations' } | ||
buildOptimisationsModule.meta = { name: NAME } | ||
|
||
export default buildOptimisationsModule |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import consola from 'consola' | ||
import { NAME } from './constants' | ||
|
||
export default consola.withScope(NAME) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,74 @@ | ||
import { ESBuildMinifyPlugin } from 'esbuild-loader' | ||
import { RuleSetUseItem } from 'webpack' | ||
import { OptimisationArgs } from '../types' | ||
import { RISK_PROFILE_SAFE } from '../constants' | ||
|
||
export default (args : OptimisationArgs) => { | ||
const { options, nuxtOptions, config, env } = args | ||
if (!config.module || !config.plugins) { | ||
export default (args: OptimisationArgs) => { | ||
const { options, nuxtOptions, config, env, logger } = args | ||
if (!config.module || !config.plugins) | ||
return | ||
} | ||
|
||
if (options.features.esbuildLoader && (env.isDev || options.profile !== 'safe')) { | ||
// we replace the babel loader with esbuild | ||
if (options.features.esbuildLoader && (env.isDev || options.profile !== RISK_PROFILE_SAFE)) { | ||
const esbuildLoaderOptions = typeof options.esbuildLoaderOptions === 'function' | ||
? options.esbuildLoaderOptions(args) | ||
: options.esbuildLoaderOptions | ||
|
||
let cacheLoader = [] | ||
// remove the nuxt js/ts loaders | ||
config.module.rules.forEach((rule, ruleKey) => { | ||
config.module.rules.map((rule) => { | ||
// nuxt js / ts file matching | ||
if (!rule.use || !Array.isArray(rule.use) || !rule.test) { | ||
return | ||
} | ||
if (!rule.use || !Array.isArray(rule.use) || !rule.test) | ||
return rule | ||
|
||
const test = rule.test as RegExp | ||
const isTypescript = test.test('test.ts') | ||
const isJavascript = test.test('test.js') | ||
|
||
if (!isJavascript && !isTypescript) | ||
return rule | ||
|
||
// @ts-ignore | ||
cacheLoader = config.module.rules[ruleKey].use.filter((use) => { | ||
return use.loader.includes('cache-loader') | ||
}) | ||
if (env.isDev && rule.test.toString() === '/\\.m?jsx?$/i') { | ||
// Need to strip the thread-loader but keep the cache loader | ||
// @ts-ignore | ||
config.module.rules[ruleKey].use = [ | ||
...cacheLoader, | ||
{ | ||
loader: 'esbuild-loader', | ||
options: { | ||
...esbuildLoaderOptions | ||
} | ||
} | ||
] | ||
} else if (rule.test.toString() === '/\\.ts$/i') { | ||
// @ts-ignore | ||
config.module.rules[ruleKey].use = [ | ||
...cacheLoader, | ||
{ | ||
loader: 'esbuild-loader', | ||
options: { | ||
loader: 'ts', | ||
...esbuildLoaderOptions | ||
} | ||
} | ||
] | ||
} else if (rule.test.toString() === '/\\.tsx$/i') { | ||
// @ts-ignore | ||
config.module.rules[ruleKey].use = [ | ||
...cacheLoader, | ||
{ | ||
loader: 'esbuild-loader', | ||
options: { | ||
loader: 'ts', | ||
...esbuildLoaderOptions | ||
} | ||
} | ||
] | ||
const babelLoaderIndex = rule.use.findIndex((use: RuleSetUseItem) => use.loader.includes('babel-loader')) | ||
if (babelLoaderIndex === -1) | ||
return rule | ||
|
||
const esbuildLoader = { | ||
loader: 'esbuild-loader', | ||
options: { | ||
...esbuildLoaderOptions, | ||
}, | ||
} | ||
|
||
// in dev we swap out babel for js | ||
if (env.isDev && isJavascript) { | ||
rule.use.splice(babelLoaderIndex, 1, esbuildLoader) | ||
logger.debug(`JS compilation: swapped out babel-loader at index ${babelLoaderIndex} for esbuild`) | ||
return rule | ||
} | ||
|
||
// always swap out typescript builds | ||
esbuildLoader.options.loader = 'ts' | ||
rule.use.splice(babelLoaderIndex, 1, esbuildLoader) | ||
// @ts-ignore | ||
const tsLoaderIndex = rule.use.findIndex((use: RuleSetUseItem) => use.loader.includes('ts-loader')) | ||
rule.use.splice(tsLoaderIndex, 1) | ||
logger.debug(`TS compilation: swapped out ts-loader at index ${tsLoaderIndex} for esbuild`) | ||
return rule | ||
}) | ||
} | ||
|
||
if (options.features.esbuildMinifier && !env.isDev && options.profile !== 'safe' && nuxtOptions.build.optimization) { | ||
// use esbuild to minify js | ||
if (options.features.esbuildMinifier && !env.isDev && options.profile !== RISK_PROFILE_SAFE && nuxtOptions.build.optimization) { | ||
const esbuildMinifyOptions = typeof options.esbuildMinifyOptions === 'function' | ||
? options.esbuildMinifyOptions(args) | ||
: options.esbuildMinifyOptions | ||
// enable esbuild minifier, replace terser | ||
nuxtOptions.build.optimization.minimize = true | ||
nuxtOptions.build.optimization.minimizer = [ | ||
new ESBuildMinifyPlugin(esbuildMinifyOptions) | ||
new ESBuildMinifyPlugin(esbuildMinifyOptions), | ||
] | ||
// make sure terser is off | ||
nuxtOptions.build.terser = false | ||
logger.debug('JS Minify: swapped out terser for esbuild minify') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.