在 Next JS 中使用 Webpack 创建将 URL 路径映射到组件的加载器

Create loader that maps URL path to a component using Webpack in Next JS

我想在 Next.js 中创建一个加载器,它使用 Webpack underhood 它是 next.config.js 配置文件,将为 /blog 路由和 Tutorial.js 加载 Blog.js /tutorial 路线。

MDX 数据在 pages/ 目录中。 pages/ 包含 blog//tutorial,它们有自己的 .mdx 个文件。

我的文件夹结构如下:

.
├── README.md
├── components
│   ├── Blog.js
│   ├── Image.js
│   └── Tutorial.js
├── jsconfig.json
├── next.config.js
├── package-lock.json
├── package.json
├── pages
│   ├── blog
│   │   ├── hello-world
│   │   │   ├── Rustin_Cohle.jpg
│   │   │   └── index.mdx
│   │   └── shit-world
│   │       └── index.mdx
│   ├── blog.js
│   ├── index.js
│   ├── tutorial
│   │   └── console-log-in-javascript
│   │       └── index.mdx
│   └── tutorial.js
├── prettier.config.js
├── src
└── utils
    ├── blog
    │   ├── getAllBlogPreviews.js
    │   ├── getStaticPaths.js
    │   └── getStaticProps.js
    ├── common
    │   ├── getAllPreviews.js
    │   ├── getStaticFilePaths.js
    │   └── getStaticFileProps.js
    ├── date.js
    ├── mdxUtils.js
    └── tutorial
        ├── getAllTutorialPreviews.js
        ├── getStaticPaths.js
        └── getStaticProps.js

我的 next.config.js 文件如下所示:

const { createLoader } = require('simple-functional-loader')
const rehypePrism = require('@mapbox/rehype-prism')
const withBundleAnalyzer = require('@next/bundle-analyzer')({
    enabled: process.env.ANALYZE === 'true',
})

module.exports = withBundleAnalyzer({
    pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
    experimental: {
        modern: true,
    },
    webpack: (config, options) => {
        config.module.rules.push({
            test: /\.(svg|png|jpe?g|gif|mp4)$/i,
            use: [
                {
                    loader: 'file-loader',
                    options: {
                        publicPath: '/_next',
                        name: 'static/media/[name].[hash].[ext]',
                    },
                },
            ],
        })

        const mdx = [
            options.defaultLoaders.babel,
            {
                loader: '@mdx-js/loader',
                options: {
                    rehypePlugins: [rehypePrism],
                },
            },
        ]

        config.module.rules.push({
            test: /\.mdx$/,
            oneOf: [
                {
                    resourceQuery: /preview/,
                    use: [
                        ...mdx,
                        createLoader(function (src) {
                            console.log('src ')
                            console.log(src)
                            console.log('src ')
                            if (src.includes('<!--more-->')) {
                                const [preview] = src.split('<!--more-->')
                                return this.callback(null, preview)
                            }

                            const [preview] = src.split('<!--/excerpt-->')
                            return this.callback(null, preview.replace('<!--excerpt-->', ''))
                        }),
                    ],
                },
                {
                    test: /blog/,
                    use: [
                        ...mdx,
                        createLoader(function (src) {
                            const content = [
                                'import Blog from "@/components/Blog"',
                                'export { getStaticProps } from "@/utils/blog/getStaticProps"',
                                'export { getStaticPaths } from "@/utils/blog/getStaticPaths"',
                                'console.log("/blog")',
                                src,
                                'export default (props) => <Blog meta={meta} {...props} />',
                            ].join('\n')

                            if (content.includes('<!--more-->')) {
                                return this.callback(null, content.split('<!--more-->').join('\n'))
                            }

                            return this.callback(null, content.replace(/<!--excerpt-->.*<!--\/excerpt-->/s, ''))
                        }),
                    ],
                },
                {
                    test: /tutorial/,
                    use: [
                        ...mdx,
                        createLoader(function (src) {
                            const content = [
                                'import Tutorial from "@/components/Tutorial"',
                                'export { getStaticProps } from "@/utils/tutorial/getStaticProps"',
                                'export { getStaticPaths } from "@/utils/tutorial/getStaticPaths"',
                                'console.log("/tutorial")',
                                src,
                                'export default (props) => <Tutorial meta={meta} {...props} />',
                            ].join('\n')

                            if (content.includes('<!--more-->')) {
                                return this.callback(null, content.split('<!--more-->').join('\n'))
                            }

                            return this.callback(null, content.replace(/<!--excerpt-->.*<!--\/excerpt-->/s, ''))
                        }),
                    ],
                },
            ],
        })

        return config
    },
})

我正在使用 test: /blog/test: /tutorial/,但它不是那样工作的。我不确定如何让它发挥作用?

我已将我的完整代码上传到 Github 的 tailwind 分支 → https://github.com/deadcoder0904/blog-mdx-next/tree/tailwind which is adapted from https://github.com/tailwindlabs/blog.tailwindcss.com

如何让 blog/ 使用 Blog.jstutorial/ 使用 Tutorial.js

我必须使用 Webpack 的包含功能,例如:

include: [path.resolve(__dirname, 'pages/blog')]

而不是

test: /blog/

& 同 tutorial.

这是提交 → https://github.com/deadcoder0904/blog-mdx-next/commit/84ad0042de3ec229dd130ef2491511c5e3090110