Compare commits
8 Commits
main
...
slorber/as
| Author | SHA1 | Date |
|---|---|---|
|
|
645bf67b50 | |
|
|
ef727ac013 | |
|
|
af7acc9e04 | |
|
|
7a5886cccf | |
|
|
f21430ea9d | |
|
|
fe60790a53 | |
|
|
0c859fe96f | |
|
|
4de1610e60 |
|
|
@ -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": [
|
||||
|
|
|
|||
|
|
@ -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": [
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -17,18 +17,15 @@ const {
|
|||
toMessageRelativeFilePath,
|
||||
} = require('@docusaurus/utils');
|
||||
|
||||
const {
|
||||
loaders: {inlineMarkdownImageFileLoader},
|
||||
} = getFileLoaderUtils();
|
||||
const {assetQuery} = getFileLoaderUtils();
|
||||
|
||||
const createJSX = (node, pathUrl) => {
|
||||
const jsxNode = node;
|
||||
jsxNode.type = 'jsx';
|
||||
jsxNode.value = `<img ${node.alt ? `alt={"${escapeHtml(node.alt)}"} ` : ''}${
|
||||
node.url
|
||||
? `src={require("${inlineMarkdownImageFileLoader}${escapePath(
|
||||
pathUrl,
|
||||
)}").default}`
|
||||
? // see https://github.com/facebook/docusaurus/pull/4708#discussion_r624515715
|
||||
`src={new URL("${escapePath(pathUrl)}?${assetQuery}", import.meta.url)}`
|
||||
: ''
|
||||
}${node.title ? ` title="${escapeHtml(node.title)}"` : ''} />`;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,9 +19,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);
|
||||
|
|
@ -47,9 +45,9 @@ function toAssetRequireNode({node, filePath, requireAssetPath}) {
|
|||
? relativeRequireAssetPath
|
||||
: `./${relativeRequireAssetPath}`;
|
||||
|
||||
const href = `require('${inlineMarkdownLinkFileLoader}${escapePath(
|
||||
const href = `new URL('${escapePath(
|
||||
relativeRequireAssetPath,
|
||||
)}').default`;
|
||||
)}?${assetQuery}', import.meta.url).toString()`;
|
||||
const children = (node.children || []).map((n) => toValue(n)).join('');
|
||||
const title = node.title ? `title="${escapeHtml(node.title)}"` : '';
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,14 @@ export default function (
|
|||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(png|jpe?g|gif)$/i,
|
||||
test: /\.(png|jpe?g)$/i,
|
||||
resourceQuery: {
|
||||
not: [/asset/],
|
||||
},
|
||||
type: 'javascript/auto',
|
||||
generator: {
|
||||
emit: !isServer,
|
||||
},
|
||||
use: [
|
||||
require.resolve('@docusaurus/lqip-loader'),
|
||||
{
|
||||
|
|
@ -40,9 +47,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,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
...{
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ export function createBaseConfig(
|
|||
chunkFilename: isProd
|
||||
? 'assets/js/[name].[contenthash:8].js'
|
||||
: '[name].js',
|
||||
assetModuleFilename: 'assets/[name]-[hash][ext]',
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -284,137 +284,157 @@ export function compile(config: Configuration[]): Promise<void> {
|
|||
});
|
||||
}
|
||||
|
||||
type AssetFolder = 'images' | 'files' | 'fonts' | 'medias';
|
||||
type AssetFolder = 'images' | 'files' | 'fonts' | 'medias' | 'svgs';
|
||||
|
||||
type FileLoaderUtils = {
|
||||
loaders: {
|
||||
file: (options: {folder: AssetFolder}) => RuleSetRule;
|
||||
url: (options: {folder: AssetFolder}) => RuleSetRule;
|
||||
inlineMarkdownImageFileLoader: string;
|
||||
inlineMarkdownLinkFileLoader: string;
|
||||
};
|
||||
assetQuery: string;
|
||||
prependAssetQueryRules: (configuration: Configuration) => Configuration;
|
||||
rules: {
|
||||
images: () => RuleSetRule;
|
||||
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 assetResourceQuery = /asset/;
|
||||
// Can this be removed? see https://github.com/facebook/docusaurus/commit/2f21d306bdd4d286cc5d25c81adaea2fc77f0474#commitcomment-50223144)
|
||||
const notAssetResourceQuery: RuleSetRule['resourceQuery'] = {not: [/asset/]};
|
||||
|
||||
// defines the path/pattern of the assets handled by webpack
|
||||
const fileLoaderFileName = (folder: AssetFolder) =>
|
||||
`${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[hash].[ext]`;
|
||||
function fileNameGenerator(folder: AssetFolder) {
|
||||
return {
|
||||
filename: `${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[hash][ext]`,
|
||||
};
|
||||
}
|
||||
|
||||
const loaders: FileLoaderUtils['loaders'] = {
|
||||
file: (options: {folder: AssetFolder}) => {
|
||||
return {
|
||||
loader: require.resolve(`file-loader`),
|
||||
options: {
|
||||
name: fileLoaderFileName(options.folder),
|
||||
function baseAssetRule(folder: AssetFolder): RuleSetRule {
|
||||
return {
|
||||
type: 'asset',
|
||||
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: 10 * 1024,
|
||||
},
|
||||
};
|
||||
},
|
||||
url: (options: {folder: AssetFolder}) => {
|
||||
return {
|
||||
loader: require.resolve(`url-loader`),
|
||||
options: {
|
||||
limit: urlLoaderLimit,
|
||||
name: fileLoaderFileName(options.folder),
|
||||
fallback: require.resolve(`file-loader`),
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
generator: fileNameGenerator(folder),
|
||||
resourceQuery: notAssetResourceQuery,
|
||||
};
|
||||
}
|
||||
|
||||
// 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=${urlLoaderLimit}&name=${fileLoaderFileName(
|
||||
'images',
|
||||
)}&fallback=file-loader!`,
|
||||
inlineMarkdownLinkFileLoader: `!file-loader?name=${fileLoaderFileName(
|
||||
'files',
|
||||
)}!`,
|
||||
};
|
||||
function imageAssetRule(): RuleSetRule {
|
||||
return {
|
||||
...baseAssetRule('images'),
|
||||
test: /\.(ico|jpg|jpeg|png|gif|webp)(\?.*)?$/i,
|
||||
};
|
||||
}
|
||||
|
||||
function fontAssetRule(): RuleSetRule {
|
||||
return {
|
||||
...baseAssetRule('fonts'),
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||
};
|
||||
}
|
||||
|
||||
function mediaAssetRule(): RuleSetRule {
|
||||
return {
|
||||
...baseAssetRule('medias'),
|
||||
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)$/i,
|
||||
type: 'asset/resource',
|
||||
};
|
||||
}
|
||||
|
||||
function svgAssetRule(): RuleSetRule {
|
||||
return {
|
||||
...baseAssetRule('svgs'),
|
||||
test: /\.svg?$/i,
|
||||
};
|
||||
}
|
||||
|
||||
// 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?$/i,
|
||||
resourceQuery: notAssetResourceQuery,
|
||||
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],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
svgAssetRule(),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
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)(\?.*)?$/,
|
||||
};
|
||||
},
|
||||
|
||||
fonts: () => {
|
||||
return {
|
||||
use: [loaders.url({folder: '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)$/,
|
||||
};
|
||||
},
|
||||
|
||||
svg: () => {
|
||||
return {
|
||||
test: /\.svg?$/,
|
||||
oneOf: [
|
||||
{
|
||||
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)$/],
|
||||
},
|
||||
},
|
||||
{
|
||||
use: [loaders.url({folder: 'images'})],
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
otherAssets: () => {
|
||||
return {
|
||||
use: [loaders.file({folder: 'files'})],
|
||||
test: /\.(pdf|doc|docx|xls|xlsx|zip|rar)$/,
|
||||
};
|
||||
},
|
||||
images: imageAssetRule,
|
||||
fonts: fontAssetRule,
|
||||
media: mediaAssetRule,
|
||||
svg: svgComponentOrAssetRule,
|
||||
files: fileAssetRule,
|
||||
};
|
||||
|
||||
return {loaders, rules};
|
||||
// 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: assetResourceQuery},
|
||||
{...fontAssetRule(), resourceQuery: assetResourceQuery},
|
||||
{...mediaAssetRule(), resourceQuery: assetResourceQuery},
|
||||
{...svgAssetRule(), resourceQuery: assetResourceQuery},
|
||||
// Fallback when ?asset is used but the file is unknown
|
||||
{
|
||||
type: 'asset/resource',
|
||||
resourceQuery: assetResourceQuery,
|
||||
generator: fileNameGenerator('files'),
|
||||
},
|
||||
],
|
||||
},
|
||||
} as Configuration);
|
||||
}
|
||||
|
||||
return {rules, assetQuery, prependAssetQueryRules};
|
||||
}
|
||||
|
||||
// Ensure the certificate and key provided are valid and if not
|
||||
|
|
|
|||
|
|
@ -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
|
||||
<img src={require('@site/static/img/myImage.png').default} />
|
||||
<img src={require('@site/static/img/myImage.png')} />
|
||||
```
|
||||
|
||||
:::
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ You can use images in Markdown, or by requiring them and using a JSX image tag:
|
|||
# My Markdown page
|
||||
|
||||
<img
|
||||
src={require('./assets/docusaurus-asset-example-banner.png').default}
|
||||
src={require('./assets/docusaurus-asset-example-banner.png')}
|
||||
alt="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
|
||||
|
||||
<a
|
||||
target="_blank"
|
||||
href={require('./assets/docusaurus-asset-example-pdf.pdf').default}>
|
||||
<a target="_blank" href={require('./assets/docusaurus-asset-example-pdf.pdf')}>
|
||||
Download this PDF
|
||||
</a>
|
||||
|
||||
|
|
@ -77,7 +75,10 @@ or
|
|||
|
||||
<a
|
||||
target="_blank"
|
||||
href={require('../../assets/docusaurus-asset-example-pdf.pdf').default}>
|
||||
href={new URL(
|
||||
'../../assets/docusaurus-asset-example-pdf.pdf',
|
||||
import.meta.url,
|
||||
).toString()}>
|
||||
Download this PDF
|
||||
</a>
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import DocusaurusImageUrl from '@site/static/img/docusaurus.png';
|
|||
```
|
||||
|
||||
```jsx title="MyComponent.js"
|
||||
<img src={require('@site/static/img/docusaurus.png').default} />
|
||||
<img src={require('@site/static/img/docusaurus.png')} />
|
||||
```
|
||||
|
||||
```jsx title="MyComponent.js"
|
||||
|
|
|
|||
Loading…
Reference in New Issue