next-compose-plugins로 다양한 plugins(withBundleAnalyzer, withAntdLess 등)를 함께 사용중인 상태에서 custom fonts를 _document.ts에서 Link로 불러와 사용하고 있었다. 이 상태에서 build를 하면 No CSS Tags warning이 나온다.
next 공식문서를 보면 HTML 링크 요소가 외부 스타일시트에 연결하는 데 사용되면서 이것이 웹 페이지의 CSS 리소스 로딩에 부정적인 영향을 미칠 수 있다고 나온다.
Why This Error Occurred
An HTML link element was used to link to an external stylesheet. This can negatively affect CSS resource loading on your web page.
참고:
https://nextjs.org/docs/messages/no-css-tags
pages/_document.tsx
import React from 'react';
import Document, { Html, Head, Main, NextScript } from 'next/document';
export default class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<link href="/assets/fonts/style.css" rel="stylesheet" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
const withPlugins = require('next-compose-plugins');
const withAntdLess = require('next-plugin-antd-less');
const withAntdLessConfig = {
// optional
modifyVars: { '@primary-color': '#348fe2' },
// optional
lessVarsFilePath: './pages/antd-custom.less',
// optional
lessVarsFilePathAppendToEndOfContent: false,
// optional https://github.com/webpack-contrib/css-loader#object
cssLoaderOptions: {},
};
const plugins = [[withBundleAnalyzer], [withAntdLess, withAntdLessConfig]];
const nextConfig = {
images: {
domains: [
'modument-openmarket-icon.s3.ap-northeast-2.amazonaws.com',
'modu-company-document.s3.ap-northeast-2.amazonaws.com',
...
],
},
webpack: (config, { webpack }) => {
const prod = process.env.NODE_ENV === 'production';
const newConfig = {
...config,
mode: prod ? 'production' : 'development',
plugins: [...config.plugins, new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /^\.\/ko$/)],
};
if (prod) {
newConfig.devtool = 'hidden-source-map';
}
return newConfig;
},
};
module.exports = withPlugins(plugins, nextConfig);
public/assets/fonts/style.css
@font-face {
font-family: 'OpenSans-Light';
src: url('OpenSans-Light.ttf') format('ttf'), url('OpenSans-Light.ttf') format('ttf'),
url('OpenSans-Light.ttf') format('truetype');
}
@font-face {
font-family: 'OpenSans-Regular';
src: url('OpenSans-Regular.ttf') format('ttf'), url('OpenSans-Regular.ttf') format('ttf'),
url('OpenSans-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'OpenSans-SemiBold';
src: url('OpenSans-SemiBold.ttf') format('ttf'), url('OpenSans-SemiBold.ttf') format('ttf'),
url('OpenSans-SemiBold.ttf') format('truetype');
}
@font-face {
font-family: 'OpenSans-Bold';
src: url('OpenSans-Bold.ttf') format('ttf'), url('OpenSans-Bold.ttf') format('ttf'),
url('OpenSans-Bold.ttf') format('truetype');
}
font 파일의 구조는 다음 블로그의 도움을 받았다.
https://stackoverflow.com/questions/61909298/how-to-use-self-hosted-fonts-face-using-nextjs
_app.tsx에서 public/assets/fonts/style.css를 불러온 뒤 build를 하면 아래와 같은 webpack error가 발생한다.
Failed to compile.
./public/assets/fonts/style.css
HookWebpackError: Module parse failed: Unexpected character '' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
-- inner error --
Error: Module parse failed: Unexpected character '' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
Generated code for /Users/juyoungjung/oms-web-admin_react/public/assets/fonts/OpenSans-Light.ttf
1 | throw new Error("Module parse failed: Unexpected character '\u0000' (1:0)\nYou may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders\n(Source code omitted for this binary file)");
_app.tsx
import '../public/assets/fonts/style.css';//이 부분
import React from 'react';
import Head from 'next/head';
import wrapper from '@redux/store/configureStore';
function OMSApp({ Component, pageProps }) {
return (
<>
<Head>
<title>MODUMENT OMS</title>
</Head>
<Component {...pageProps} />
</>
);
}
export default wrapper.withRedux(OMSApp);
이는 next.config.js에 다음과 같은 module.rules설정을 해주면 해결된다.
next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
const withPlugins = require('next-compose-plugins');
const withAntdLess = require('next-plugin-antd-less');
const withAntdLessConfig = {
...
};
const plugins = [[withBundleAnalyzer], [withAntdLess, withAntdLessConfig]];
const nextConfig = {
images: {
domains: [
...
],
},
webpack: (config, { webpack }) => {
const prod = process.env.NODE_ENV === 'production';
const newConfig = {
...config,
mode: prod ? 'production' : 'development',
module: {
rules: [ //이 부분
...config.module.rules,
{
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 100000,
name: '[name].[ext]',
},
},
},
],
},
plugins: [...config.plugins, new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /^\.\/ko$/)],
};
if (prod) {
newConfig.devtool = 'hidden-source-map';
}
return newConfig;
},
async rewrites() {
return [
{
source: '/:path*',
destination: `https://oms.modument.co.kr/:path*`,
},
// {
// source: '/:path*',
// destination: `http://192.168.0.17:7000/:path*`,
// },
];
},
};
module.exports = withPlugins(plugins, nextConfig);
참고: https://stackoverflow.com/questions/59455259/nextjs-module-parse-failed-unexpected-character-70
다음 스크린샷과 같이 font를 읽어오지 못하는 문제가 발생했다.
이는 font path를 제대로 읽어오지 못해 발생하는 문제로 다음과 같이 font path를 수정하니 해결되었다.
public/assets/fonts/style.css
@font-face {
font-family: 'OpenSans-Light';
src: url('OpenSans-Light.ttf') format('ttf');
}
@font-face {
font-family: 'OpenSans-Regular';
src: url('OpenSans-Regular.ttf') format('ttf');
}
@font-face {
font-family: 'OpenSans-SemiBold';
src: url('OpenSans-SemiBold.ttf') format('ttf');
}
@font-face {
font-family: 'OpenSans-Bold';
src: url('OpenSans-Bold.ttf') format('ttf');
}