UNPKG

@docusaurus/utils

Version:

Node utility functions for Docusaurus packages.

157 lines (140 loc) 4.83 kB
/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ import path from 'path'; import {escapePath} from './pathUtils'; import { WEBPACK_URL_LOADER_LIMIT, OUTPUT_STATIC_ASSETS_DIR_NAME, } from './constants'; import type {RuleSetRule, LoaderContext} from 'webpack'; export type WebpackCompilerName = 'server' | 'client'; export function getWebpackLoaderCompilerName( context: LoaderContext<unknown>, ): WebpackCompilerName { // eslint-disable-next-line no-underscore-dangle const compilerName = context._compiler?.name; switch (compilerName) { case 'server': case 'client': return compilerName; default: throw new Error( `Cannot get valid Docusaurus webpack compiler name. Found compilerName=${compilerName}`, ); } } type AssetFolder = 'images' | 'files' | 'fonts' | 'medias'; type FileLoaderUtils = { loaders: { file: (options: {folder: AssetFolder}) => RuleSetRule; url: (options: {folder: AssetFolder}) => RuleSetRule; inlineMarkdownImageFileLoader: string; inlineMarkdownAssetImageFileLoader: string; inlineMarkdownLinkFileLoader: string; }; rules: { images: () => RuleSetRule; fonts: () => RuleSetRule; media: () => RuleSetRule; otherAssets: () => RuleSetRule; }; }; // TODO this historical code is quite messy // We should try to get rid of it and move to assets pipeline function createFileLoaderUtils({ isServer, }: { isServer: boolean; }): FileLoaderUtils { // Files/images < urlLoaderLimit will be inlined as base64 strings directly in // the html const urlLoaderLimit = WEBPACK_URL_LOADER_LIMIT; const fileLoaderFileName = (folder: AssetFolder) => path.posix.join( OUTPUT_STATIC_ASSETS_DIR_NAME, folder, '[name]-[contenthash].[ext]', ); const loaders: FileLoaderUtils['loaders'] = { file: (options: {folder: AssetFolder}) => ({ loader: require.resolve(`file-loader`), options: { name: fileLoaderFileName(options.folder), emitFile: !isServer, }, }), url: (options: {folder: AssetFolder}) => ({ loader: require.resolve('url-loader'), options: { limit: urlLoaderLimit, name: fileLoaderFileName(options.folder), fallback: require.resolve('file-loader'), emitFile: !isServer, }, }), // TODO avoid conflicts with the ideal-image plugin // TODO this may require a little breaking change for ideal-image users? // Maybe with the ideal image plugin, all md images should be "ideal"? // This is used to force url-loader+file-loader on markdown images // https://webpack.js.org/concepts/loaders/#inline inlineMarkdownImageFileLoader: `!${escapePath( require.resolve('url-loader'), )}?limit=${urlLoaderLimit}&name=${fileLoaderFileName( 'images', )}&fallback=${escapePath(require.resolve('file-loader'))}${ isServer ? `&emitFile=false` : '' }!`, inlineMarkdownAssetImageFileLoader: `!${escapePath( require.resolve('file-loader'), )}?name=${fileLoaderFileName('images')}${ isServer ? `&emitFile=false` : '' }!`, inlineMarkdownLinkFileLoader: `!${escapePath( require.resolve('file-loader'), )}?name=${fileLoaderFileName('files')}${ isServer ? `&emitFile=false` : '' }!`, }; const rules: FileLoaderUtils['rules'] = { /** * Loads image assets, inlines images via a data URI if they are below * the size threshold */ images: () => ({ use: [loaders.url({folder: 'images'})], test: /\.(?:ico|jpe?g|png|gif|webp|avif)(?:\?.*)?$/i, }), fonts: () => ({ use: [loaders.url({folder: 'fonts'})], test: /\.(?:woff2?|eot|ttf|otf)$/i, }), /** * Loads audio and video and inlines them via a data URI if they are below * the size threshold */ media: () => ({ use: [loaders.url({folder: 'medias'})], test: /\.(?:mp4|avi|mov|mkv|mpg|mpeg|vob|wmv|m4v|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/i, }), otherAssets: () => ({ use: [loaders.file({folder: 'files'})], test: /\.(?:pdf|docx?|xlsx?|zip|rar)$/i, }), }; return {loaders, rules}; } const FileLoaderUtilsMap = { server: createFileLoaderUtils({isServer: true}), client: createFileLoaderUtils({isServer: false}), }; /** * Returns unified loader configurations to be used for various file types. * Inspired by https://github.com/gatsbyjs/gatsby/blob/8e6e021014da310b9cc7d02e58c9b3efe938c665/packages/gatsby/src/utils/webpack-utils.ts#L447 */ export function getFileLoaderUtils(isServer: boolean): FileLoaderUtils { return isServer ? FileLoaderUtilsMap.server : FileLoaderUtilsMap.client; }