UNPKG

@lipemat/js-boilerplate

Version:

Dependencies and scripts for a no config JavaScript app

225 lines (202 loc) 6.54 kB
import {existsSync} from 'fs'; import {resolve} from 'path'; import {type Configuration as WebpackConfig} from 'webpack'; import type {Configuration as DevServerConfig} from 'webpack-dev-server'; import type {BabelConfig} from '../config/babel.config'; import type {JestConfig} from '../config/jest.config'; import {getPackageConfig} from './package-config'; import type {EntriesConfig} from '../config/entries.config'; import type {PostCSSConfig} from '../config/postcss.config'; import type {CssLoaderConfig} from '../config/css-loader.config'; // Must be required to avoid issues with browserslist. const browserslist = require( 'browserslist' ); type Configs = { 'babel.config': BabelConfig; 'css-loader.config': CssLoaderConfig; 'dev-server.config': DevServerConfig; 'entries.config': EntriesConfig; 'jest.config': JestConfig; 'postcss.config': PostCSSConfig; 'webpack.dist': WebpackConfig; }; const {dependencies, devDependencies, workingDirectory, packageDirectory} = getPackageConfig(); const extensions = [ ...Object.keys( dependencies ?? {} ).filter( name => name.includes( 'js-boilerplate-' ) ), ...Object.keys( devDependencies ?? {} ).filter( name => name.includes( 'js-boilerplate-' ) ), ]; /** * Check to see if a local config file exists. * * @param {string} fileName * @param {boolean} inWorkingDirectory - Look in working directory instead of their /config directory * * @return {boolean} */ export function hasLocalOverride( fileName: string, inWorkingDirectory: boolean = false ): boolean { let hasLocal = false; try { if ( inWorkingDirectory ) { require( resolve( workingDirectory, fileName ) ); hasLocal = true; } else { require( resolve( packageDirectory + '/config', fileName ) ); hasLocal = true; } } catch ( e ) { if ( e instanceof Error ) { if ( ! ( 'code' in e ) || 'MODULE_NOT_FOUND' !== e.code ) { console.error( e ); } } } return hasLocal; } /** * Get a config from our /config directory merged with any * matching configuration from the project directory. * * For instance, if we have a file named config/babel.config.js in our project, * we will merge the contents with our config/babel.config.js in favor of whatever * is specified with the project's file. * * If the `module.exports` is a function, the existing configuration will be passed * as the only argument. Otherwise, standard `module.exports` are also supported. * * @example ```ts * // standard * module.export = { * externals: {extra: 'Extra'} * } * // function * module.exports = function(config) { * return { * externals: {...config.externals, extra: 'Extra'} * } * } * ``` * * @param {string} fileName * * @return {Object} */ export function getConfig<T extends keyof Configs>( fileName: T ): Configs[T] { let mergedConfig = require( '../config/' + fileName ) as Configs[T]; mergedConfig = {...mergedConfig, ...getExtensionsConfig<Configs[T]>( fileName, mergedConfig )}; try { const localConfig = require( resolve( packageDirectory + '/config', fileName ) ); if ( 'function' === typeof localConfig ) { mergedConfig = {...mergedConfig, ...localConfig( mergedConfig )}; } else { mergedConfig = {...mergedConfig, ...localConfig}; } } catch ( e ) { if ( e instanceof Error ) { if ( ! ( 'code' in e ) || 'MODULE_NOT_FOUND' !== e.code ) { console.error( e ); } } } return mergedConfig; } /** * Get a config from any existing extension's /config directories * merged into one. * * @param {string} fileName * @param {Object} defaultConfig - Default config from this package. * Used for passing to an extension callback. * * @see getConfig * * @return {Object} */ export function getExtensionsConfig<T extends object>( fileName: string, defaultConfig: T ): T { let mergedConfig: T = {} as T; extensions.forEach( extension => { try { let extensionConfig = require( extension + '/config/' + fileName ); // For ES Modules, we need to use the default export. if ( 'default' in extensionConfig ) { extensionConfig = extensionConfig.default; } if ( 'function' === typeof extensionConfig ) { mergedConfig = {...mergedConfig, ...extensionConfig( {...defaultConfig, ...mergedConfig} )}; } else { mergedConfig = {...mergedConfig, ...extensionConfig}; } } catch ( e ) { if ( e instanceof Error ) { if ( ! ( 'code' in e ) || 'MODULE_NOT_FOUND' !== e.code ) { console.error( e ); } } } } ); return mergedConfig; } /** * Get the path to the "tsconfig.json" file if it exists. * * 1. The working directory. * 2. The package directory. * * The package directory takes priority over the working directory. * * * @return {string} */ export function getTsConfigFile(): string { const possibles = [ // Backward compatible for before @lipemat/eslint-config version 3. resolve( workingDirectory + '/tsconfig.json' ), resolve( packageDirectory + '/tsconfig.json' ), ].filter( existsSync ); let tsConfig = ''; possibles.forEach( filePath => { tsConfig = filePath; } ); return tsConfig; } /** * Get the browserslist from the current project. * * - If specified using standard browserslist config, we will use that. * * @link https://github.com/browserslist/browserslist#config-file */ export function getBrowsersList(): readonly string[] { const projectBrowsersList = browserslist(); if ( browserslist( browserslist.defaults ) === projectBrowsersList ) { const wp = [ ...require( '@wordpress/browserslist-config' ) ]; return adjustBrowserslist( wp ); } return projectBrowsersList; } /** * If the browserslist is not specified, we fall back to WordPress defaults. * * - Return the default browserslist if the current project does not specify one. * - Return false if a browserslist is specified. * * Used in cases where we can fall back to standard browserslist config if the project * has not specified one. * * @deprecated Use getBrowsersList instead. * * @link https://github.com/browserslist/browserslist#config-file * * @return {boolean | string[]} */ export const getDefaultBrowsersList = (): false | string[] => { if ( browserslist( browserslist.defaults ) === browserslist() ) { const wp = [ ...require( '@wordpress/browserslist-config' ) ]; return adjustBrowserslist( wp ); } return false; }; /** * Adjust the browserslist to include our defaults. */ export function adjustBrowserslist( browserRules: string[] ): string[] { return browserRules; }