Sergey Krylov 8246f41dde feat: add devServer option
BREAKING CHANGE: remove `port` option, use `devServer` option instead
2024-04-04 06:13:56 +03:00

174 lines
4.0 KiB
TypeScript

import getCache from 'cache';
import * as fs from 'fs';
import path from 'path';
import process from 'process';
import type webpack from 'webpack';
import createDevServer from 'dev-server';
import createLoaders from 'loaders';
import getOptimization from 'optimization';
import createOutput from 'output';
import createPlugins from 'plugins';
import createResolvers from 'resolvers';
import type { WebpackMode, WebpackOptions, WebpackPaths } from 'types';
const getDefaultEntryPath = (rootDir: string, some?: string[] | string): string[] | string => {
if (Array.isArray(some)) {
// @ts-ignore
return some.map((entry) => getDefaultEntryPath(rootDir, entry));
}
if (some && path.isAbsolute(some)) {
return some;
}
const definedFile = some && path.resolve(rootDir, some);
const indexTsx = path.resolve(rootDir, 'index.tsx');
const indexTs = path.resolve(rootDir, 'index.ts');
const indexJsx = path.resolve(rootDir, 'index.jsx');
const indexJs = path.resolve(rootDir, 'index.js');
switch (true) {
case definedFile && fs.existsSync(definedFile):
return definedFile;
case fs.existsSync(indexTsx):
return indexTsx;
case fs.existsSync(indexTs):
return indexTs;
case fs.existsSync(indexJsx):
return indexJsx;
case fs.existsSync(indexJs):
return indexJs;
default:
throw new Error(`Has no ${definedFile ?? 'index.tsx/index.ts/index.jsx/index.js'} file in ${rootDir} directory`);
}
};
const getDefaultPath = ({ root, defaultDirectory, currentPath }: Record<string, string | undefined>) => {
if (!currentPath) {
// @ts-ignore
return path.resolve(root, defaultDirectory);
}
if (path.isAbsolute(currentPath)) {
return currentPath;
}
// @ts-ignore
return path.resolve(root, currentPath);
};
const getDefaultPaths = (initialPaths?: WebpackPaths): WebpackPaths => {
const root = initialPaths?.root ?? path.resolve(process.cwd());
const publicPath = getDefaultPath({
root,
defaultDirectory: 'public',
currentPath: initialPaths?.public,
});
const src = getDefaultPath({
root,
defaultDirectory: 'src',
currentPath: initialPaths?.src,
});
const assets = getDefaultPath({
root: publicPath,
defaultDirectory: 'assets',
currentPath: initialPaths?.assets,
});
const build = getDefaultPath({
root,
defaultDirectory: 'build',
currentPath: initialPaths?.build,
});
const html = getDefaultPath({
root: publicPath,
defaultDirectory: 'index.html',
currentPath: initialPaths?.html,
});
const entry = getDefaultEntryPath(src, initialPaths?.entry);
return {
root,
public: publicPath,
assets,
src,
entry,
build,
html,
};
};
const getDefaultMode = (): WebpackMode => {
const isServe = process.argv.slice(2)[0] === 'serve';
return isServe ? 'development' : 'production';
};
const createConfig = (params?: WebpackOptions): webpack.Configuration => {
const {
mode = getDefaultMode(),
analyze = false,
mainLoader,
svgLoader,
devtool = 'inline-source-map',
plugins,
loaders,
devServer,
} = params ?? {};
const {
assets,
html,
build,
root,
entry,
public: publicPath,
src,
} = getDefaultPaths(params?.paths);
const options: WebpackOptions = {
mode,
analyze,
mainLoader,
svgLoader,
paths: {
assets,
html,
build,
root,
entry,
src,
public: publicPath,
},
plugins,
loaders,
devServer,
};
const isDev = mode === 'development';
return {
context: process.cwd(),
mode,
entry,
output: createOutput(options),
plugins: createPlugins(options),
module: {
rules: createLoaders(options),
},
resolve: createResolvers(options),
devtool: isDev ? devtool : false,
devServer: createDevServer(options),
// eslint-disable-next-line no-undefined
optimization: !isDev ? getOptimization(options) : undefined,
cache: getCache(options),
};
};
export default createConfig;