是否有办法使用物质化CDN与Next.js?



我正在构建一个Next.js应用程序,并希望与它一起使用Materialize CDN。在React中,我只需要在public/index.html文件中添加CDN链接,就可以了。Next似乎没有这个,我被困在如何做到这一点。

我试过了

npm install materialize-css@next --save

然后像这样导入到pages/_app.tsx中:

import 'materialize-css/dist/css/materialize.min.css';
import 'materialize-css'

当它仅仅是第一个导入时,它工作得很好,但是当我导入第二个来添加JS时,它给我这个错误:

Server Error
ReferenceError: window is not defined
This error happened while generating the page. Any console logs will be displayed in the terminal window.

同样,通过这种导入,我不能对CSS进行任何自定义,这就是为什么我想使用CDN。我已经做了好几天了,还是没有运气。

通过CDN使用Materialize

正如Daniel在他的回答中提到的,你可以在你的自定义_document中添加CDN链接,这样CSS和JavaScript都可以在浏览器中正确加载。

// /pages/_document.js
class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"
/>
</Head>
<body>
<Main />
<NextScript />
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</body>
</Html>
);
}
}

因为Materialize在内部使用Web api,所以您需要访问useEffect内部附加到window的Materialize实例。这可以防止ReferenceError: window is not defined错误,当页面被Next.js在服务器上预渲染时。

下面是一个如何在渲染旋转木马的组件中使用Materialize的小示例。

const MaterializeCarousel = () => {
useEffect(() => {
const elems = document.querySelectorAll('.carousel');
const instances = window.M.Carousel.init(elems);
}, []);
return (
<div className="carousel">
<a className="carousel-item" href="#one!"><img src="https://lorempixel.com/250/250/nature/1" /></a>
<a className="carousel-item" href="#two!"><img src="https://lorempixel.com/250/250/nature/2" /></a>
<a className="carousel-item" href="#three!"><img src="https://lorempixel.com/250/250/nature/3" /></a>
<a className="carousel-item" href="#four!"><img src="https://lorempixel.com/250/250/nature/4" /></a>
<a className="carousel-item" href="#five!"><img src="https://lorempixel.com/250/250/nature/5" /></a>
</div>
);
};

使用Materialize通过npm包

另一个选择是通过它的npm包materialize-css使用这个库。

您首先需要导入全局CSS,就像您在_app中所做的那样。

import 'materialize-css/dist/css/materialize.min.css';

JavaScript代码不能在这里加载,正如前面提到的,它使用了不能在服务器上工作的Web api。

相反,以相同的carousel组件为例,您应该在useEffect中动态导入materialize-css,以便它只在客户端加载。

const MaterializeCarousel = () => {
useEffect(() => {
const init = async () => {
const M = await import('materialize-css');
const elems = document.querySelectorAll('.carousel');
const instances = M.Carousel.init(elems);
};
init();
}, []);
return (
<div className="carousel">
<a className="carousel-item" href="#one!"><img src="https://lorempixel.com/250/250/nature/1" /></a>
<a className="carousel-item" href="#two!"><img src="https://lorempixel.com/250/250/nature/2" /></a>
<a className="carousel-item" href="#three!"><img src="https://lorempixel.com/250/250/nature/3" /></a>
<a className="carousel-item" href="#four!"><img src="https://lorempixel.com/250/250/nature/4" /></a>
<a className="carousel-item" href="#five!"><img src="https://lorempixel.com/250/250/nature/5" /></a>
</div>
);
};

与其在_app.tsx文件中做,不如在_document.js文件中做。这个文件是你在NextJS项目中增加html和body标签的地方。需要注意的是,它必须是.js文件,而不是。tsx.

这个文件默认不存在于你的项目中,它是由nextJS自动生成的,但你可以在pages文件夹中创建它来覆盖默认的CDN,并在那里导入CDN。

您可以在官方文档中找到_document.js模板和更多信息。

最新更新