mac*_*ost 5 javascript reactjs webpack gatsby
我正在尝试对现有的 Gatsby 插件进行改进,并且我想通过其配置条目将 React 组件传递给插件gatsby-config.js:
plugins: [
{
resolve: `gatsby-plugin-modal-routing`,
options: { someComponent: SomeComponentClassOrFunction }
},
Run Code Online (Sandbox Code Playgroud)
但是,我遇到的问题是我不知道如何使它工作。
如果我尝试将组件本身作为插件配置的一部分传递,它似乎与 JSON 进行了序列化,从而导致该类成为无用的对象。所以看来我必须传递一个路径字符串。
plugins: [
{
resolve: `gatsby-plugin-modal-routing`,
options: {
modalComponentPath: path.join(__dirname, 'src/components/SomeComponent.js')
}
},
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试传递路径,则无法弄清楚如何使用它来加载插件内的组件。我试过使用动态节点导入(即。import(path).then(component => ...))...
path.join-ed的路径__dirnamesrc/components/SomeComponent)./src/components/SomeComponent).js我不确定这是否是应用程序与插件的不同路径的某种问题,或者是否存在其他问题,但import无论如何使用似乎都不是Gatsby 式的解决方案。
所以,然后我发现了传递到插件中的loadPage和loadPageSync函数......但那些也失败了。我尝试的每条路径都会导致组件返回......但它是一个“找不到页面”的组件(大概是因为我尝试传入的组件尚未作为页面添加)。
这似乎应该是一个简单的问题,至少对于之前研究过 Gatsby 插件的任何人来说:如果您希望插件将组件作为输入(作为函数/类或作为模块的路径)……您如何在插件中实际使用该组件?
我正在寻找的只是一个基本模式或对现有 Gatsby 插件中的一行的引用,该插件采用一个组件,或者类似的东西(我可以查找任何细节)。
这似乎应该是一个简单的问题
我自己尝试这个时也有同样的想法。好家伙。
// gatsby-node.js
const { DefinePlugin } = require('webpack')
const path = require('path')
exports.onCreateWebpackConfig = ({ actions }, { componentPath }) => {
actions.setWebpackConfig({
plugins: [
new DefinePlugin({
'___COMPONENT___': JSON.stringify(componentPath)
})
]
})
}
Run Code Online (Sandbox Code Playgroud)
// gatsby-ssr
export const onRenderBody = ({ setPreBodyComponents }) => {
const Component = require(___COMPONENT___).default
setPreBodyComponents([<Component />])
}
Run Code Online (Sandbox Code Playgroud)
Gatsby 配置似乎没有传递函数(我可以发誓它曾经发誓过),因此将 React 组件直接传递给您的自定义插件是不可能的。它必须是您的组件的路径。
// gatsby-config.js
{
resolve: 'my-custom-plugin',
options: {
componentPath: path.join(__dirname, './my-component.js')
}
}
Run Code Online (Sandbox Code Playgroud)
你没有说你是否在gatsby-nodeor 中使用组件gatsby-browser/ssr,但我认为它是后者,因为在 Node 中动态地需要东西是非常简单的:
// gatsby-ssr
export const onRenderBody = ({ setPreBodyComponents }) => {
const Component = require(___COMPONENT___).default
setPreBodyComponents([<Component />])
}
Run Code Online (Sandbox Code Playgroud)
...虽然它不理解 JSX 或 ESM,但这是一个不同的问题。
gatsby-browser/ssr是用webpack运行的,所以模块格式不是问题。但import(componentPath)不会工作:
import() 中的动态表达式
不可能使用完全动态的导入语句,例如
import(foo). 因为 foo 可能是系统或项目中任何文件的任何路径。
好的,我想这样的事情应该有效:
// gatsby-browser
import('./my-dir' + componentPath)
Run Code Online (Sandbox Code Playgroud)
不,因为 webpack 会尝试从插件所在的任何位置(即node_modules或plugins目录)解决此问题,我们不会要求用户将他们的自定义组件放在node_modules.
那这个怎么办?
// gatsby-browser
import(process.cwd() + componentPath) // nope
Run Code Online (Sandbox Code Playgroud)
我们又回到了起点——webpack 不喜欢完整的动态路径!而且即使这可行,这也是一个糟糕的主意,因为 webpack 会尝试捆绑整个工作目录。
只有我们可以事先将路径编码为静态字符串,这样 webpack 才能读取该代码——就像使用webpack.DefinePlugin定义环境变量一样。幸运的是,我们可以在 gatsby-node.js 中做到这一点:
// gatsby-config.js
{
resolve: 'my-custom-plugin',
options: {
componentPath: path.join(__dirname, './my-component.js')
}
}
Run Code Online (Sandbox Code Playgroud)
最后
// gatsby-browser
// eslint throw error for unknown var, so disable it
// eslint-disable-next-line
import(___CURRENT_DIR___ + componentPath) // works, but don't do this
Run Code Online (Sandbox Code Playgroud)
但是由于我们可以直接在 中访问用户选项gatsby-node,让我们对整个路径进行编码:
// gatsby-node.js
const { DefinePlugin } = require('webpack')
- const path = require('path')
- exports.onCreateWebpackConfig = ({ actions }) => {
+ exports.onCreateWebpackConfig = ({ actions }, { componentPath }) => {
actions.setWebpackConfig({
plugins: [
new DefinePlugin({
- '___CURRENT_DIR___': JSON.stringify(process.cwd())
+ '___COMPONENT___': JSON.stringify(componentPath)
})
]
})
}
Run Code Online (Sandbox Code Playgroud)
回到 gatsby-browser.js:
// gatsby-browser
// I pick a random API to test, can't imagine why one would import a module in this API
export const onRouteUpdate = async () => {
// eslint-disable-next-line
const { default: Component } = await import(___COMPONENT___)
console.log(Component) // works
}
Run Code Online (Sandbox Code Playgroud)
为了完整起见,让我们在 gatby-ssr 中尝试相同的技巧:
// gatsby-node.js
function consume(component) {
const Component = require(component)
}
Run Code Online (Sandbox Code Playgroud)
……它失败了。
为什么?如果一个人足够好奇,他们可能会去挖掘 Gatsby 代码,看看 gatsby-ssr 的处理方式与 gatsby-browser 有何不同,但可惜我不想那样做。
不要害怕,我们还有一个绝招。Webpack 的 require 也可以动态导入模块,但不是异步的。由于gatsby-ssr不在浏览器中运行,所以我不太关心异步性。
export const onRenderBody = ({ setPreBodyComponents }) => {
const Component = require(___COMPONENT___).default
setPreBodyComponents([<Component />]) // works
}
Run Code Online (Sandbox Code Playgroud)
现在它起作用了。
假设我们在两者中都需要这个组件,gatsby-ssr并且gatsby-browser- 也require(...)可以使用gatsby-browser吗?
export const onRouteUpdate = async () => {
// eslint-disable-next-line
const { default: Component } = require(___COMPONENT___)
console.log(Component) // yes
}
Run Code Online (Sandbox Code Playgroud)
有用。
import(..) 对比 require()虽然import()确实动态加载内容,但它更像是一种代码拆分工具。除了异步性之外,还有一些不同之处:
usingimport('./my-dir' + componentPath)将把里面的所有文件打包./my-dir成一个块。我们可以使用魔术注释来排除/包含内容。
require(...) 只会将所需的组件内联到调用它的任何块中。
| 归档时间: |
|
| 查看次数: |
436 次 |
| 最近记录: |