UNPKG

dn-middleware-webpack5

Version:

--- group: middleware name: webpack5 title: Webpack5 ---

231 lines (202 loc) 7.41 kB
import * as fs from "fs"; import * as path from "path"; import * as Dawn from "@dawnjs/types"; import globby from "globby"; import getPublicUrlOrPath from "react-dev-utils/getPublicUrlOrPath"; import { FileInfo } from "../types"; // import type { Stats } from "webpack/types"; export const getExistFile = ({ cwd, files, returnRelative, }: { cwd: string; files: string[]; returnRelative: boolean; }) => { for (const file of files) { const absFilePath = path.join(cwd, file); if (fs.existsSync(absFilePath)) { return returnRelative ? file : absFilePath; } } }; // We use `PUBLIC_URL` enviroinfernment variable or "homepage" field to // "public path" at which the app is served. // webpack needs to know it to put the right <script> hrefs into HTML even in // single-page apps that may serve index.html for nested URLs like /todos/42. // We can't use a relative path in HTML because we don't want to load something // like /todos/42/static/js/bundle.7289d.js. We have to know the root. export const getPublicPath = (ctx: Dawn.Context) => ctx.publicPath || ctx.publicPath === "" ? ctx.publicPath : getPublicUrlOrPath(process.env.NODE_ENV === "development", process.env.PUBLIC_URL, ""); // ./src/foo.js => foo const getFilenameByPath = (f: string) => path.basename(f).split(".")[0]; // format entry and template export const formatReglikeObject = (params: Record<string, string> | any[] | string) => { const paramsMap: Record<string, string> = {}; if (typeof params === "string") { paramsMap[getFilenameByPath(params)] = params; } else if (Array.isArray(params)) { params.forEach((e: any) => { paramsMap[getFilenameByPath(e)] = e; }); } else { Object.assign(paramsMap, params); } const nameFileList: FileInfo[] = []; Object.entries(paramsMap).forEach(([nameExpr, fileExpr]) => { const files = globby.sync(fileExpr); files.forEach(file => { const paths = file.split("/").reverse()?.map(getFilenameByPath); const name = nameExpr.replace(/\((\d+)\)/g, (_, index) => { return paths[index]; }); nameFileList.push({ name, file }); }); }); return nameFileList; }; export function formatNullStringToList<T = string>(params?: T | T[] | null): T[] { if (!params) return []; else if (Array.isArray(params)) { return params; } return [params]; } export function formatWebpackMessages({ warnings, errors }: { warnings?: any[]; errors?: any[] }) { const result = { errors: Array.isArray(errors) ? errors?.map(message => (typeof message === "string" ? formatMessage(message) : formatMessageObj(message))) : [], warnings: Array.isArray(warnings) ? warnings?.map(message => (typeof message === "string" ? formatMessage(message) : formatMessageObj(message))) : [], }; if (result.errors.some(isLikelyASyntaxError)) { // If there are any syntax errors, show just them. // This prevents a confusing ESLint parsing error // preceding a much more useful Babel syntax error. result.errors = result.errors.filter(isLikelyASyntaxError); } return result; } /** * @param {number} size the size in bytes * @returns {string} the formatted size */ export function formatSize(size: number) { if (typeof size !== "number" || Number.isNaN(size) === true) { return "unknown size"; } if (size <= 0) { return "0 bytes"; } const abbreviations = ["bytes", "KiB", "MiB", "GiB"]; const index = Math.floor(Math.log(size) / Math.log(1024)); return `${+(size / 1024 ** index).toPrecision(3)} ${abbreviations[index]}`; } export function makeRow(a: string, b: string): string { return ` ${a}\t ${b}`; } // export function printError(stats: Stats, ctx: Dawn.Context) { // const info = stats.toJson(); // // Compilation errors (missing modules, syntax errors, etc) // if (stats.hasErrors()) { // ctx.console.error("error"); // ctx.console.error(info.errors); // } // // Compilation warnings // if (stats.hasWarnings()) { // ctx.console.error("warning"); // ctx.console.warn(info.warnings); // } // } const friendlySyntaxErrorLabel = "Syntax error:"; function isLikelyASyntaxError(message: string) { return message.indexOf(friendlySyntaxErrorLabel) !== -1; } // Cleans up webpack error messages. // eslint-disable-next-line no-unused-vars function formatMessage(message: string) { if (!message) return ""; let lines = message ? message?.split("\n") : []; if (lines.length > 2 && lines[1] === "") { // Remove extra newline. lines.splice(1, 1); } // Remove webpack-specific loader notation from filename. // Before: // ./~/css-loader!./~/postcss-loader!./src/App.css // After: // ./src/App.css if (lines[0]?.lastIndexOf("!") !== -1) { lines[0] = lines[0]?.substr(lines[0]?.lastIndexOf("!") + 1); } // Remove unnecessary stack added by `thread-loader` var threadLoaderIndex = -1; lines.forEach(function (line, index) { if (threadLoaderIndex !== -1) { return; } if (line.indexOf("from thread-loader (worker") !== -1) { threadLoaderIndex = index; } }); if (threadLoaderIndex !== -1) { lines = lines.slice(0, threadLoaderIndex); } lines = lines.filter(function (line) { // Webpack adds a list of entry points to warning messages: // @ ./src/index.js // @ multi react-scripts/~/react-dev-utils/webpackHotDevClient.js ... // It is misleading (and unrelated to the warnings) so we clean it up. // It is only useful for syntax errors but we have beautiful frames for them. return line.indexOf(" @ ") !== 0; }); // line #0 is filename // line #1 is the main error message if (!lines[0] || !lines[1]) { return lines.join("\n"); } // Cleans up verbose "module not found" messages for files and packages. if (lines[1].indexOf("Module not found: ") === 0) { lines = [ lines[0], // Clean up message because "Module not found: " is descriptive enough. lines[1] .replace("Cannot resolve 'file' or 'directory' ", "") .replace("Cannot resolve module ", "") .replace("Error: ", "") .replace("[CaseSensitivePathsPlugin] ", ""), ]; } // Cleans up syntax error messages. if (lines[1].indexOf("Module build failed: ") === 0) { lines[1] = lines[1].replace("Module build failed: SyntaxError:", friendlySyntaxErrorLabel); } // Clean up export errors. // TODO: we should really send a PR to Webpack for this. const exportError = /\s*(.+?)\s*(")?export '(.+?)' was not found in '(.+?)'/; if (lines[1].match(exportError)) { lines[1] = lines[1].replace(exportError, "$1 '$4' does not contain an export named '$3'."); } // Reassemble the message. message = lines.join("\n"); // Internal stacks are generally useless so we strip them... with the // exception of stacks containing `webpack:` because they're normally // from user code generated by WebPack. For more information see // https://github.com/facebook/create-react-app/pull/1050 message = message.replace(/^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm, ""); // at ... ...:x:y return message.trim(); } type ErrObj = { moduleIdentifier?: string; moduleName?: string; loc?: string; message?: string; }; function formatMessageObj({ moduleName, loc, message }: ErrObj) { return moduleName + "(" + loc + ")" + "\n" + message + "\n"; }