From 4de1610e60597f69431573e24481926512e0f0c1 Mon Sep 17 00:00:00 2001 From: slorber Date: Wed, 28 Apr 2021 11:35:08 +0200 Subject: [PATCH 1/7] WIP attempt to use webpack 5 asset modules --- .../src/remark/transformImage/index.js | 8 +- .../src/remark/transformLinks/index.js | 6 +- .../src/index.ts | 6 +- packages/docusaurus/src/commands/build.ts | 6 + packages/docusaurus/src/commands/start.ts | 5 + packages/docusaurus/src/webpack/base.ts | 3 +- packages/docusaurus/src/webpack/utils.ts | 206 ++++++++++++------ 7 files changed, 157 insertions(+), 83 deletions(-) diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js b/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js index 1a017033a7c3..cf2088e424c6 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js @@ -13,17 +13,13 @@ const escapeHtml = require('escape-html'); const {getFileLoaderUtils} = require('@docusaurus/core/lib/webpack/utils'); const {posixPath, toMessageRelativeFilePath} = require('@docusaurus/utils'); -const { - loaders: {inlineMarkdownImageFileLoader}, -} = getFileLoaderUtils(); +const {assetQuery} = getFileLoaderUtils(); const createJSX = (node, pathUrl) => { const jsxNode = node; jsxNode.type = 'jsx'; jsxNode.value = ``; if (jsxNode.url) { diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js b/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js index 1ac3a0890098..ad6dfd33247d 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js @@ -15,9 +15,7 @@ const escapeHtml = require('escape-html'); const {toValue} = require('../utils'); const {getFileLoaderUtils} = require('@docusaurus/core/lib/webpack/utils'); -const { - loaders: {inlineMarkdownLinkFileLoader}, -} = getFileLoaderUtils(); +const {assetQuery} = getFileLoaderUtils(); async function ensureAssetFileExist(fileSystemAssetPath, sourceFilePath) { const assetExists = await fs.pathExists(fileSystemAssetPath); @@ -43,7 +41,7 @@ function toAssetRequireNode({node, filePath, requireAssetPath}) { ? relativeRequireAssetPath : `./${relativeRequireAssetPath}`; - const href = `require('${inlineMarkdownLinkFileLoader}${relativeRequireAssetPath}').default`; + const href = `require('${relativeRequireAssetPath}?${assetQuery}').default`; const children = (node.children || []).map((n) => toValue(n)).join(''); const title = node.title ? `title="${escapeHtml(node.title)}"` : ''; diff --git a/packages/docusaurus-plugin-ideal-image/src/index.ts b/packages/docusaurus-plugin-ideal-image/src/index.ts index c3ddf74b9311..b1e91b0628c0 100644 --- a/packages/docusaurus-plugin-ideal-image/src/index.ts +++ b/packages/docusaurus-plugin-ideal-image/src/index.ts @@ -31,7 +31,11 @@ export default function ( module: { rules: [ { - test: /\.(png|jpe?g|gif)$/i, + test: /\.(png|jpe?g)$/i, + type: 'javascript/auto', + generator: { + emit: !isServer, + }, use: [ require.resolve('@docusaurus/lqip-loader'), { diff --git a/packages/docusaurus/src/commands/build.ts b/packages/docusaurus/src/commands/build.ts index 7074f706b6da..0a5c1c8fb7d4 100644 --- a/packages/docusaurus/src/commands/build.ts +++ b/packages/docusaurus/src/commands/build.ts @@ -24,6 +24,7 @@ import { applyConfigurePostCss, applyConfigureWebpack, compile, + getFileLoaderUtils, } from '../webpack/utils'; import CleanWebpackPlugin from '../webpack/plugins/CleanWebpackPlugin'; import {loadI18n} from '../server/i18n'; @@ -197,6 +198,11 @@ async function buildLocale({ } }); + // Add the very high-priority rules triggered by using a resourceQuery like ?asset + const {prependAssetQueryRules} = getFileLoaderUtils(); + clientConfig = prependAssetQueryRules(clientConfig); + serverConfig = prependAssetQueryRules(serverConfig); + // Make sure generated client-manifest is cleaned first so we don't reuse // the one from previous builds. if (await fs.pathExists(clientManifestPath)) { diff --git a/packages/docusaurus/src/commands/start.ts b/packages/docusaurus/src/commands/start.ts index 2f045b48f101..48f71d61f137 100644 --- a/packages/docusaurus/src/commands/start.ts +++ b/packages/docusaurus/src/commands/start.ts @@ -29,6 +29,7 @@ import { applyConfigureWebpack, applyConfigurePostCss, getHttpsConfig, + getFileLoaderUtils, } from '../webpack/utils'; import {getCLIOptionHost, getCLIOptionPort} from './commandUtils'; import {getTranslationsLocaleDirPath} from '../server/translations/translations'; @@ -157,6 +158,10 @@ export default async function start( } }); + // Add the very high-priority rules triggered by using a resourceQuery like ?asset + const {prependAssetQueryRules} = getFileLoaderUtils(); + config = prependAssetQueryRules(config); + // https://webpack.js.org/configuration/dev-server const devServerConfig: WebpackDevServer.Configuration = { ...{ diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts index a43019b69ef9..77d4457fe700 100644 --- a/packages/docusaurus/src/webpack/base.ts +++ b/packages/docusaurus/src/webpack/base.ts @@ -108,6 +108,7 @@ export function createBaseConfig( chunkFilename: isProd ? 'assets/js/[name].[contenthash:8].js' : '[name].js', + assetModuleFilename: 'assets/[hash][ext][query]', publicPath: baseUrl, }, // Don't throw warning when asset created is over 250kb @@ -191,7 +192,7 @@ export function createBaseConfig( fileLoaderUtils.rules.fonts(), fileLoaderUtils.rules.media(), fileLoaderUtils.rules.svg(), - fileLoaderUtils.rules.otherAssets(), + fileLoaderUtils.rules.files(), { test: /\.(j|t)sx?$/, exclude: excludeJS, diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index f9eda08d13d7..fa6a3b61d243 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -284,9 +284,11 @@ export function compile(config: Configuration[]): Promise { }); } -type AssetFolder = 'images' | 'files' | 'fonts' | 'medias'; +type AssetFolder = 'images' | 'files' | 'fonts' | 'medias' | 'svgs' | 'other'; type FileLoaderUtils = { + assetQuery: string; + prependAssetQueryRules: (configuration: Configuration) => Configuration; loaders: { file: (options: {folder: AssetFolder}) => RuleSetRule; url: (options: {folder: AssetFolder}) => RuleSetRule; @@ -298,34 +300,66 @@ type FileLoaderUtils = { fonts: () => RuleSetRule; media: () => RuleSetRule; svg: () => RuleSetRule; - otherAssets: () => RuleSetRule; + files: () => RuleSetRule; }; }; // Inspired by https://github.com/gatsbyjs/gatsby/blob/8e6e021014da310b9cc7d02e58c9b3efe938c665/packages/gatsby/src/utils/webpack-utils.ts#L447 export function getFileLoaderUtils(): FileLoaderUtils { - // files/images < 10kb will be inlined as base64 strings directly in the html - const urlLoaderLimit = 10000; + // Asset queries are used to force the usage of the file as an asset + // In some case we want to opt-out o + // - converting an image to an ideal-image + // - converting an SVG to a React component + // - other cases + const assetQuery = 'asset'; + const assetQueryRegex = /asset/; + + // Threshold for datauri/file (previously set on url-loader) + // files/images < 10kb will be inlined as base64 strings directly in the JS bundle + // See https://webpack.js.org/guides/asset-modules/#general-asset-type + const dataUrlMaxSize = 10000; // defines the path/pattern of the assets handled by webpack - const fileLoaderFileName = (folder: AssetFolder) => + const generatedFileName = (folder: AssetFolder) => `${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[hash].[ext]`; + function fileNameGenerator(folder: AssetFolder) { + return { + filename: generatedFileName(folder), + }; + } + + function baseAssetRule(folder: AssetFolder): RuleSetRule { + return { + parser: { + dataUrlCondition: { + // Threshold for datauri/file (previously set on url-loader) + // files/images < 10kb will be inlined as base64 strings directly in the JS bundle + // See https://webpack.js.org/guides/asset-modules/#general-asset-type + maxSize: dataUrlMaxSize, + }, + }, + generator: fileNameGenerator(folder), + }; + } + const loaders: FileLoaderUtils['loaders'] = { + // TODO deprecated file: (options: {folder: AssetFolder}) => { return { loader: require.resolve(`file-loader`), options: { - name: fileLoaderFileName(options.folder), + name: generatedFileName(options.folder), }, }; }, url: (options: {folder: AssetFolder}) => { + // TODO deprecated return { loader: require.resolve(`url-loader`), options: { - limit: urlLoaderLimit, - name: fileLoaderFileName(options.folder), + limit: dataUrlMaxSize, + name: generatedFileName(options.folder), fallback: require.resolve(`file-loader`), }, }; @@ -336,85 +370,115 @@ export function getFileLoaderUtils(): FileLoaderUtils { // 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: `!url-loader?limit=${urlLoaderLimit}&name=${fileLoaderFileName( + inlineMarkdownImageFileLoader: `!url-loader?limit=${dataUrlMaxSize}&name=${generatedFileName( 'images', )}&fallback=file-loader!`, - inlineMarkdownLinkFileLoader: `!file-loader?name=${fileLoaderFileName( + inlineMarkdownLinkFileLoader: `!file-loader?name=${generatedFileName( 'files', )}!`, }; - const rules: FileLoaderUtils['rules'] = { - /** - * Loads image assets, inlines images via a data URI if they are below - * the size threshold - */ - images: () => { - return { - use: [loaders.url({folder: 'images'})], - test: /\.(ico|jpg|jpeg|png|gif|webp)(\?.*)?$/, - }; - }, + function imageAssetRule(): RuleSetRule { + return { + ...baseAssetRule('images'), + test: /\.(ico|jpg|jpeg|png|gif|webp)(\?.*)?$/, + }; + } - fonts: () => { - return { - use: [loaders.url({folder: 'fonts'})], - test: /\.(woff|woff2|eot|ttf|otf)$/, - }; - }, + function fontAssetRule(): RuleSetRule { + return { + ...baseAssetRule('fonts'), + test: /\.(woff|woff2|eot|ttf|otf)$/, + }; + } - /** - * Loads audio and video and inlines them via a data URI if they are below - * the size threshold - */ - media: () => { - return { - use: [loaders.url({folder: 'medias'})], - test: /\.(mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/, - }; - }, + function mediaAssetRule(): RuleSetRule { + return { + ...baseAssetRule('medias'), + test: /\.(mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/, + }; + } - svg: () => { - return { - test: /\.svg?$/, - oneOf: [ - { - use: [ - { - loader: '@svgr/webpack', - options: { - prettier: false, - svgo: true, - svgoConfig: { - plugins: [{removeViewBox: false}], - }, - titleProp: true, - ref: ![path], + function fileAssetRule(): RuleSetRule { + return { + ...baseAssetRule('files'), + test: /\.(pdf|doc|docx|xls|xlsx|zip|rar)$/, + type: 'asset/resource', + }; + } + + function svgAssetRule(): RuleSetRule { + return { + ...baseAssetRule('svgs'), + test: /\.svg?$/, + }; + } + + // We convert SVG to React component when required from code only + // We don't convert SVG to React components when referenced in CSS + function svgComponentOrAssetRule(): RuleSetRule { + return { + test: /\.svg?$/, + oneOf: [ + { + // only convert for those extensions + issuer: /\.(ts|tsx|js|jsx|md|mdx)$/, + use: [ + { + loader: '@svgr/webpack', + options: { + prettier: false, + svgo: true, + svgoConfig: { + plugins: [{removeViewBox: false}], }, + titleProp: true, + ref: ![path], }, - ], - // We don't want to use SVGR loader for non-React source code - // ie we don't want to use SVGR for CSS files... - issuer: { - and: [/\.(ts|tsx|js|jsx|md|mdx)$/], }, - }, + ], + }, + svgAssetRule(), + ], + }; + } + + const rules: FileLoaderUtils['rules'] = { + images: imageAssetRule, + fonts: fontAssetRule, + media: mediaAssetRule, + svg: svgComponentOrAssetRule, + files: fileAssetRule, + }; + + // Those rules are triggered conditionally when using ?asset + // They must be added at the very beginning of the rules array + // Even before the rules prepended by other plugins + // This is a replacement for Webpack 4 file/url-loader webpack queries + function prependAssetQueryRules(configuration: Configuration): Configuration { + return mergeWithCustomize({ + customizeArray: customizeArray({ + 'module.rules': CustomizeRule.Prepend, + }), + })(configuration, { + module: { + rules: [ + {...imageAssetRule(), resourceQuery: assetQueryRegex}, + {...fontAssetRule(), resourceQuery: assetQueryRegex}, + {...mediaAssetRule(), resourceQuery: assetQueryRegex}, + {...svgAssetRule(), resourceQuery: assetQueryRegex}, + // Fallback when ?asset is used but the file is unknown { - use: [loaders.url({folder: 'images'})], + type: 'asset/resource', + resourceQuery: assetQueryRegex, + generator: fileNameGenerator('files'), }, ], - }; - }, - - otherAssets: () => { - return { - use: [loaders.file({folder: 'files'})], - test: /\.(pdf|doc|docx|xls|xlsx|zip|rar)$/, - }; - }, - }; + }, + } as Configuration); + } - return {loaders, rules}; + return {loaders, rules, assetQuery, prependAssetQueryRules}; } // Ensure the certificate and key provided are valid and if not From 0c859fe96f37878e6b04e44afc99e43d9e04b06c Mon Sep 17 00:00:00 2001 From: slorber Date: Fri, 30 Apr 2021 11:29:49 +0200 Subject: [PATCH 2/7] fix ideal-image warning due to missing hash: > Conflict: Multiple assets emit different content to the same filename assets/ideal-img/datagit.100.png see https://github.com/facebook/docusaurus/pull/4089#discussion_r622013656 --- packages/docusaurus-plugin-ideal-image/src/index.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/docusaurus-plugin-ideal-image/src/index.ts b/packages/docusaurus-plugin-ideal-image/src/index.ts index b1e91b0628c0..6b0b46444968 100644 --- a/packages/docusaurus-plugin-ideal-image/src/index.ts +++ b/packages/docusaurus-plugin-ideal-image/src/index.ts @@ -32,10 +32,6 @@ export default function ( rules: [ { test: /\.(png|jpe?g)$/i, - type: 'javascript/auto', - generator: { - emit: !isServer, - }, use: [ require.resolve('@docusaurus/lqip-loader'), { @@ -44,9 +40,8 @@ export default function ( emitFile: !isServer, // don't emit for server-side rendering disable: !isProd, adapter: require('@docusaurus/responsive-loader/sharp'), - name: isProd - ? 'assets/ideal-img/[name].[hash:hex:7].[width].[ext]' - : 'assets/ideal-img/[name].[width].[ext]', + name: + 'assets/ideal-img/[name].[contenthash:8].[width].[ext]', ...options, }, }, From fe60790a530a4f151a89e4923e6ee8e68810a25d Mon Sep 17 00:00:00 2001 From: slorber Date: Fri, 30 Apr 2021 16:12:57 +0200 Subject: [PATCH 3/7] Fix asset modules bug: use "not asset" resourceQuery, remove .default --- .../src/remark/transformImage/index.js | 2 +- .../src/remark/transformLinks/index.js | 2 +- .../src/index.ts | 9 ++++++++- packages/docusaurus/src/webpack/base.ts | 2 +- packages/docusaurus/src/webpack/utils.ts | 20 +++++++++++-------- website/docs/docusaurus-core.md | 2 +- .../markdown-features-assets.mdx | 8 +++----- website/docs/static-assets.md | 2 +- 8 files changed, 28 insertions(+), 19 deletions(-) diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js b/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js index cf2088e424c6..e5b0a1938203 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js @@ -19,7 +19,7 @@ const createJSX = (node, pathUrl) => { const jsxNode = node; jsxNode.type = 'jsx'; jsxNode.value = ``; if (jsxNode.url) { diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js b/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js index ad6dfd33247d..0ba646793e5b 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js @@ -41,7 +41,7 @@ function toAssetRequireNode({node, filePath, requireAssetPath}) { ? relativeRequireAssetPath : `./${relativeRequireAssetPath}`; - const href = `require('${relativeRequireAssetPath}?${assetQuery}').default`; + const href = `require('${relativeRequireAssetPath}?${assetQuery}')`; const children = (node.children || []).map((n) => toValue(n)).join(''); const title = node.title ? `title="${escapeHtml(node.title)}"` : ''; diff --git a/packages/docusaurus-plugin-ideal-image/src/index.ts b/packages/docusaurus-plugin-ideal-image/src/index.ts index 6b0b46444968..d3fc2fb0362c 100644 --- a/packages/docusaurus-plugin-ideal-image/src/index.ts +++ b/packages/docusaurus-plugin-ideal-image/src/index.ts @@ -32,6 +32,13 @@ export default function ( rules: [ { test: /\.(png|jpe?g)$/i, + resourceQuery: { + not: [/asset/], + }, + type: 'javascript/auto', + generator: { + emit: !isServer, + }, use: [ require.resolve('@docusaurus/lqip-loader'), { @@ -41,7 +48,7 @@ export default function ( disable: !isProd, adapter: require('@docusaurus/responsive-loader/sharp'), name: - 'assets/ideal-img/[name].[contenthash:8].[width].[ext]', + 'assets/ideal-img/[name]-[contenthash:8].[width].[ext]', ...options, }, }, diff --git a/packages/docusaurus/src/webpack/base.ts b/packages/docusaurus/src/webpack/base.ts index 77d4457fe700..4767221b67f1 100644 --- a/packages/docusaurus/src/webpack/base.ts +++ b/packages/docusaurus/src/webpack/base.ts @@ -108,7 +108,7 @@ export function createBaseConfig( chunkFilename: isProd ? 'assets/js/[name].[contenthash:8].js' : '[name].js', - assetModuleFilename: 'assets/[hash][ext][query]', + assetModuleFilename: 'assets/[name]-[hash][ext]', publicPath: baseUrl, }, // Don't throw warning when asset created is over 250kb diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index fa6a3b61d243..8dabb0f9772e 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -284,7 +284,7 @@ export function compile(config: Configuration[]): Promise { }); } -type AssetFolder = 'images' | 'files' | 'fonts' | 'medias' | 'svgs' | 'other'; +type AssetFolder = 'images' | 'files' | 'fonts' | 'medias' | 'svgs'; type FileLoaderUtils = { assetQuery: string; @@ -312,7 +312,9 @@ export function getFileLoaderUtils(): FileLoaderUtils { // - converting an SVG to a React component // - other cases const assetQuery = 'asset'; - const assetQueryRegex = /asset/; + const assetResourceQuery = /asset/; + // Can this be removed? see https://github.com/facebook/docusaurus/commit/2f21d306bdd4d286cc5d25c81adaea2fc77f0474#commitcomment-50223144) + const notAssetResourceQuery: RuleSetRule['resourceQuery'] = {not: [/asset/]}; // Threshold for datauri/file (previously set on url-loader) // files/images < 10kb will be inlined as base64 strings directly in the JS bundle @@ -321,7 +323,7 @@ export function getFileLoaderUtils(): FileLoaderUtils { // defines the path/pattern of the assets handled by webpack const generatedFileName = (folder: AssetFolder) => - `${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[hash].[ext]`; + `${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[hash][ext]`; function fileNameGenerator(folder: AssetFolder) { return { @@ -340,6 +342,7 @@ export function getFileLoaderUtils(): FileLoaderUtils { }, }, generator: fileNameGenerator(folder), + resourceQuery: notAssetResourceQuery, }; } @@ -419,6 +422,7 @@ export function getFileLoaderUtils(): FileLoaderUtils { function svgComponentOrAssetRule(): RuleSetRule { return { test: /\.svg?$/, + resourceQuery: notAssetResourceQuery, oneOf: [ { // only convert for those extensions @@ -463,14 +467,14 @@ export function getFileLoaderUtils(): FileLoaderUtils { })(configuration, { module: { rules: [ - {...imageAssetRule(), resourceQuery: assetQueryRegex}, - {...fontAssetRule(), resourceQuery: assetQueryRegex}, - {...mediaAssetRule(), resourceQuery: assetQueryRegex}, - {...svgAssetRule(), resourceQuery: assetQueryRegex}, + {...imageAssetRule(), resourceQuery: assetResourceQuery}, + {...fontAssetRule(), resourceQuery: assetResourceQuery}, + {...mediaAssetRule(), resourceQuery: assetResourceQuery}, + {...svgAssetRule(), resourceQuery: assetResourceQuery}, // Fallback when ?asset is used but the file is unknown { type: 'asset/resource', - resourceQuery: assetQueryRegex, + resourceQuery: assetResourceQuery, generator: fileNameGenerator('files'), }, ], diff --git a/website/docs/docusaurus-core.md b/website/docs/docusaurus-core.md index 6344bfcf9a3e..2e38ad249f25 100644 --- a/website/docs/docusaurus-core.md +++ b/website/docs/docusaurus-core.md @@ -303,7 +303,7 @@ In most cases, you don't need `useBaseUrl`. Prefer a `require()` call for [assets](./guides/markdown-features/markdown-features-assets.mdx): ```jsx - + ``` ::: diff --git a/website/docs/guides/markdown-features/markdown-features-assets.mdx b/website/docs/guides/markdown-features/markdown-features-assets.mdx index 83d6514c7741..2fa4dd8a8121 100644 --- a/website/docs/guides/markdown-features/markdown-features-assets.mdx +++ b/website/docs/guides/markdown-features/markdown-features-assets.mdx @@ -28,7 +28,7 @@ You can use images in Markdown, or by requiring them and using a JSX image tag: # My Markdown page Example banner @@ -64,9 +64,7 @@ In the same way, you can link to existing assets by requiring them and using the ```mdx # My Markdown page - + Download this PDF @@ -77,7 +75,7 @@ or + href={require('../../assets/docusaurus-asset-example-pdf.pdf')}> Download this PDF diff --git a/website/docs/static-assets.md b/website/docs/static-assets.md index 9224e655776c..07e8f3a2f5f9 100644 --- a/website/docs/static-assets.md +++ b/website/docs/static-assets.md @@ -27,7 +27,7 @@ import DocusaurusImageUrl from '@site/static/img/docusaurus.png'; ``` ```jsx title="MyComponent.js" - + ``` ```jsx title="MyComponent.js" From f21430ea9da04f9c811283b793074862960f9c06 Mon Sep 17 00:00:00 2001 From: slorber Date: Fri, 30 Apr 2021 16:47:27 +0200 Subject: [PATCH 4/7] typo --- packages/docusaurus/src/webpack/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index 8dabb0f9772e..8e6a4785b925 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -333,6 +333,7 @@ export function getFileLoaderUtils(): FileLoaderUtils { function baseAssetRule(folder: AssetFolder): RuleSetRule { return { + type: 'asset', parser: { dataUrlCondition: { // Threshold for datauri/file (previously set on url-loader) From 7a5886cccf91bac360427d4318fe39e1598e1c69 Mon Sep 17 00:00:00 2001 From: slorber Date: Fri, 30 Apr 2021 17:14:15 +0200 Subject: [PATCH 5/7] webpack asset modules cleanup --- .../templates/bootstrap/package.json | 4 +- .../templates/classic/package.json | 4 +- .../templates/facebook/package.json | 4 +- packages/docusaurus/src/webpack/utils.ts | 55 +------------------ 4 files changed, 6 insertions(+), 61 deletions(-) diff --git a/packages/docusaurus-init/templates/bootstrap/package.json b/packages/docusaurus-init/templates/bootstrap/package.json index ee895876ddf5..3a7e040de22a 100644 --- a/packages/docusaurus-init/templates/bootstrap/package.json +++ b/packages/docusaurus-init/templates/bootstrap/package.json @@ -19,10 +19,8 @@ "@mdx-js/react": "^1.6.21", "@svgr/webpack": "^5.5.0", "clsx": "^1.1.1", - "file-loader": "^6.2.0", "react": "^17.0.1", - "react-dom": "^17.0.1", - "url-loader": "^4.1.1" + "react-dom": "^17.0.1" }, "browserslist": { "production": [ diff --git a/packages/docusaurus-init/templates/classic/package.json b/packages/docusaurus-init/templates/classic/package.json index 80135fec8811..13fda1aaddc1 100644 --- a/packages/docusaurus-init/templates/classic/package.json +++ b/packages/docusaurus-init/templates/classic/package.json @@ -19,10 +19,8 @@ "@mdx-js/react": "^1.6.21", "@svgr/webpack": "^5.5.0", "clsx": "^1.1.1", - "file-loader": "^6.2.0", "react": "^17.0.1", - "react-dom": "^17.0.1", - "url-loader": "^4.1.1" + "react-dom": "^17.0.1" }, "browserslist": { "production": [ diff --git a/packages/docusaurus-init/templates/facebook/package.json b/packages/docusaurus-init/templates/facebook/package.json index 3c559709ddca..04a231b9d743 100644 --- a/packages/docusaurus-init/templates/facebook/package.json +++ b/packages/docusaurus-init/templates/facebook/package.json @@ -23,10 +23,8 @@ "@mdx-js/react": "^1.6.21", "@svgr/webpack": "^5.5.0", "clsx": "^1.1.1", - "file-loader": "^6.2.0", "react": "^17.0.1", - "react-dom": "^17.0.1", - "url-loader": "^4.1.1" + "react-dom": "^17.0.1" }, "devDependencies": { "@babel/eslint-parser": "^7.13.10", diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index 8e6a4785b925..3ff6b99350c9 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -289,12 +289,6 @@ type AssetFolder = 'images' | 'files' | 'fonts' | 'medias' | 'svgs'; type FileLoaderUtils = { assetQuery: string; prependAssetQueryRules: (configuration: Configuration) => Configuration; - loaders: { - file: (options: {folder: AssetFolder}) => RuleSetRule; - url: (options: {folder: AssetFolder}) => RuleSetRule; - inlineMarkdownImageFileLoader: string; - inlineMarkdownLinkFileLoader: string; - }; rules: { images: () => RuleSetRule; fonts: () => RuleSetRule; @@ -316,18 +310,10 @@ export function getFileLoaderUtils(): FileLoaderUtils { // Can this be removed? see https://github.com/facebook/docusaurus/commit/2f21d306bdd4d286cc5d25c81adaea2fc77f0474#commitcomment-50223144) const notAssetResourceQuery: RuleSetRule['resourceQuery'] = {not: [/asset/]}; - // Threshold for datauri/file (previously set on url-loader) - // files/images < 10kb will be inlined as base64 strings directly in the JS bundle - // See https://webpack.js.org/guides/asset-modules/#general-asset-type - const dataUrlMaxSize = 10000; - // defines the path/pattern of the assets handled by webpack - const generatedFileName = (folder: AssetFolder) => - `${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[hash][ext]`; - function fileNameGenerator(folder: AssetFolder) { return { - filename: generatedFileName(folder), + filename: `${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[hash][ext]`, }; } @@ -339,7 +325,7 @@ export function getFileLoaderUtils(): FileLoaderUtils { // Threshold for datauri/file (previously set on url-loader) // files/images < 10kb will be inlined as base64 strings directly in the JS bundle // See https://webpack.js.org/guides/asset-modules/#general-asset-type - maxSize: dataUrlMaxSize, + maxSize: 10 * 1024, }, }, generator: fileNameGenerator(folder), @@ -347,41 +333,6 @@ export function getFileLoaderUtils(): FileLoaderUtils { }; } - const loaders: FileLoaderUtils['loaders'] = { - // TODO deprecated - file: (options: {folder: AssetFolder}) => { - return { - loader: require.resolve(`file-loader`), - options: { - name: generatedFileName(options.folder), - }, - }; - }, - url: (options: {folder: AssetFolder}) => { - // TODO deprecated - return { - loader: require.resolve(`url-loader`), - options: { - limit: dataUrlMaxSize, - name: generatedFileName(options.folder), - fallback: require.resolve(`file-loader`), - }, - }; - }, - - // TODO find a better solution to 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: `!url-loader?limit=${dataUrlMaxSize}&name=${generatedFileName( - 'images', - )}&fallback=file-loader!`, - inlineMarkdownLinkFileLoader: `!file-loader?name=${generatedFileName( - 'files', - )}!`, - }; - function imageAssetRule(): RuleSetRule { return { ...baseAssetRule('images'), @@ -483,7 +434,7 @@ export function getFileLoaderUtils(): FileLoaderUtils { } as Configuration); } - return {loaders, rules, assetQuery, prependAssetQueryRules}; + return {rules, assetQuery, prependAssetQueryRules}; } // Ensure the certificate and key provided are valid and if not From ef727ac013532821f30137c2c9873a4b231c9111 Mon Sep 17 00:00:00 2001 From: slorber Date: Thu, 13 May 2021 17:34:03 +0200 Subject: [PATCH 6/7] replace require() by new URL() --- .../docusaurus-mdx-loader/src/remark/transformImage/index.js | 5 ++++- .../docusaurus-mdx-loader/src/remark/transformLinks/index.js | 4 ++-- .../guides/markdown-features/markdown-features-assets.mdx | 5 ++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js b/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js index 55ad4b128ec0..4286a6338d7e 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js +++ b/packages/docusaurus-mdx-loader/src/remark/transformImage/index.js @@ -23,7 +23,10 @@ const createJSX = (node, pathUrl) => { const jsxNode = node; jsxNode.type = 'jsx'; jsxNode.value = ``; if (jsxNode.url) { diff --git a/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js b/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js index d75bdcb576bd..51e3e583d048 100644 --- a/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js +++ b/packages/docusaurus-mdx-loader/src/remark/transformLinks/index.js @@ -45,9 +45,9 @@ function toAssetRequireNode({node, filePath, requireAssetPath}) { ? relativeRequireAssetPath : `./${relativeRequireAssetPath}`; - const href = `require('${escapePath( + const href = `new URL('${escapePath( relativeRequireAssetPath, - )}?${assetQuery}')`; + )}?${assetQuery}', import.meta.url).toString()`; const children = (node.children || []).map((n) => toValue(n)).join(''); const title = node.title ? `title="${escapeHtml(node.title)}"` : ''; diff --git a/website/docs/guides/markdown-features/markdown-features-assets.mdx b/website/docs/guides/markdown-features/markdown-features-assets.mdx index 2fa4dd8a8121..b9398ca9499b 100644 --- a/website/docs/guides/markdown-features/markdown-features-assets.mdx +++ b/website/docs/guides/markdown-features/markdown-features-assets.mdx @@ -75,7 +75,10 @@ or + href={new URL( + '../../assets/docusaurus-asset-example-pdf.pdf', + import.meta.url, + ).toString()}> Download this PDF From 645bf67b5021b76ea5e772f75d21f8bdb2bdb689 Mon Sep 17 00:00:00 2001 From: slorber Date: Thu, 13 May 2021 17:38:39 +0200 Subject: [PATCH 7/7] case-insensitive webpack rule regexes --- packages/docusaurus/src/webpack/utils.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/docusaurus/src/webpack/utils.ts b/packages/docusaurus/src/webpack/utils.ts index 3ff6b99350c9..2e892b590a1e 100644 --- a/packages/docusaurus/src/webpack/utils.ts +++ b/packages/docusaurus/src/webpack/utils.ts @@ -336,28 +336,28 @@ export function getFileLoaderUtils(): FileLoaderUtils { function imageAssetRule(): RuleSetRule { return { ...baseAssetRule('images'), - test: /\.(ico|jpg|jpeg|png|gif|webp)(\?.*)?$/, + test: /\.(ico|jpg|jpeg|png|gif|webp)(\?.*)?$/i, }; } function fontAssetRule(): RuleSetRule { return { ...baseAssetRule('fonts'), - test: /\.(woff|woff2|eot|ttf|otf)$/, + test: /\.(woff|woff2|eot|ttf|otf)$/i, }; } function mediaAssetRule(): RuleSetRule { return { ...baseAssetRule('medias'), - test: /\.(mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/, + test: /\.(mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/i, }; } function fileAssetRule(): RuleSetRule { return { ...baseAssetRule('files'), - test: /\.(pdf|doc|docx|xls|xlsx|zip|rar)$/, + test: /\.(pdf|doc|docx|xls|xlsx|zip|rar)$/i, type: 'asset/resource', }; } @@ -365,7 +365,7 @@ export function getFileLoaderUtils(): FileLoaderUtils { function svgAssetRule(): RuleSetRule { return { ...baseAssetRule('svgs'), - test: /\.svg?$/, + test: /\.svg?$/i, }; } @@ -373,7 +373,7 @@ export function getFileLoaderUtils(): FileLoaderUtils { // We don't convert SVG to React components when referenced in CSS function svgComponentOrAssetRule(): RuleSetRule { return { - test: /\.svg?$/, + test: /\.svg?$/i, resourceQuery: notAssetResourceQuery, oneOf: [ {