//tips
//smart contract
viewportはhtmlのなかのmetaタグ内に書かれる記述で、ブラウザのレンダリング範囲のことを指す。
<meta name="viewport" content="width=480">とすると、幅480pxの仮想的なウインドウが作られ、ブラウザはそこにレンダリングする。
この時、viewportの幅が実際の液晶画面よりも大きければviewportが当然はみ出すことになるのでブラウザ側がズームアップやダウンにより調整している。
content="width=device-width">と指定した場合はviewportの幅は端末やブラウザアプリ毎によって異なる。
モバイル端末において、viewportメタタグで width の記載がない場合、「ウィンドウ幅によってページコンテンツが隠されないの最小の横幅」か「デフォルト値・980px」の大きな方が適応されるよう。
<Head>
<meta name="viewport" content="initial-scale=1, width=device-width" />
</Head>
デフォルトでテーマというものがmaterial-uiには存在しており、これはデフォルトで設定されているcssといえば理解しやすい。
例えば色などのデフォルトのテーマを変更する場合に、colorプロパティで対応できるなら、特に問題ないが、対応ができない場合は、createThemeとThemeProviderを使って色を変えることになる。
Secondaryカラーを自分の意図したものに変えると下記のようになる。
const testTheme = createTheme({
palette: {
secondary: {
main: '#000',
},
},
});
const App = () => {
return (
<ThemeProvider theme={testTheme}>
<Typography color={'secondary'}></Typography>
</ThemeProvider>
);
ThemeProviderのなかのthemeに作成したテーマを格納する。
参考:
https://zenn.dev/hunbari_front/articles/3fea37ef98c718
<ThemeProvider theme={theme}>
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
ここでのCssBaselineは各ブラウザーの差異を平均化させる normalize.css のような役割を果たしてくれるとのこと。
CssBaseline is sort of css reset added to the <head /> of your document. If you are familiar with similar approaches like normalize.css which adds some default visual styling to default elements, resets paddings and etc ...
Material-UI provides some reset styles as you can observe here CssBasline.js mainly box-sizing and body font color and background color
<CssBaseline />
参考:
https://stackoverflow.com/questions/57058299/what-does-the-cssbaseline-class-do
CacheProviderとThemeProviderの違いは引数として受け渡しが必要なものとそうでないものという考え形でいいのか。
<Component {...pageProps} />
</ThemeProvider>
</CacheProvider>
);
}
MyApp.propTypes = {
Component: PropTypes.elementType.isRequired,
emotionCache: PropTypes.object,
pageProps: PropTypes.object.isRequired,
};
ここからは_document.js の確認。これが一番謎が多いところ。
このスクリプトが作成されるのは、アプリケーションの <html> タグと <body> タグを拡張するため。Next.js ページは周囲のドキュメントのマークアップの定義を省略するためこれが必要になるよう。
Next.jsのページでは<html>や<body>などの基本的なマークアップはデフォルトで書かなくてよい設定になっており、全体の文書構造をカスタマイズしたい場合pages/_document.jsファイルで<Document>コンポーネントを拡張することになるということ。
全ページ共通でheadタグ内で読み込みしたい場合などはDocumentコンポーネントをカスタマイズすることで実装する。Documentコンポーネントはブラウザでは実行されず、サーバサイドでのみ実行される。
参考:
https://nextjs-ja-translation-docs.vercel.app/docs/advanced-features/custom-document
export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
{/* PWA primary color */}
<meta name="theme-color" content={theme.palette.primary.main} />
<link rel="shortcut icon" href="/static/favicon.ico" />
favicon.icoはホームページのシンボル(アイコン)として使われる、画像ファイルのことで、お気に入りに登録したときなどにホームページタイトルの横に表示される小さな画像のこと。
MuiデフォルトのRobotoフォント。
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
/>
{/* Inject MUI styles first to match with the prepend: true configuration. */}
{this.props.emotionStyleTags}
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
アイコンとフォントのために新たにこのスクリプトを作っているのかな。
getInitialProps は、ページ内のサーバーサイドレンダリングを可能にし、初期データを追加出来るようにする。つ既にデータが追加されているページをサーバーから送信する。
app→page→documentの引数渡しが終わると、app→page→documentの順でレンダリングされる。
MyDocument.getInitialProps = async (ctx) => {
Ctxの内容は下記。
getInitialProps は context という単一の引数を受け取り、この context は以下のプロパティを持つオブジェクト。
pathname - 現在のルート。これは /pages にあるページのパス。
query - オブジェクトとしてパース(解析)される URL のクエリ文字列セクション。
asPath - ブラウザに表示される実際のパスの文字列(クエリを含む)。
req - HTTP リクエストオブジェクト(サーバのみ)。
res - HTTP レスポンスオブジェクト(サーバのみ)。
err - レンダリング中にエラーが発生した場合のエラーオブジェクト。
もうこれらのメソッドは古く非推奨であるが、同期的にレンダリングを実行でき、その中でrenderpage内にproprsを渡す流れがわかる。
const originalRenderPage = ctx.renderPage
// Run the React rendering logic synchronously
ctx.renderPage = () =>
originalRenderPage({
// Useful for wrapping the whole react tree
enhanceApp: (App) => App,
// Useful for wrapping in a per-page basis
enhanceComponent: (Component) => Component,
})
// Run the parent `getInitialProps`, it now includes the custom `renderPage`
const initialProps = await Document.getInitialProps(ctx)
return initialProps
}
今回のスクリプトではenhanceComponent: (Component) => Component,の部分を加工し、 <App emotionCache={cache} {...props} />;などのようにしている。プロパティの中にemotionCache={cache} を入れたいため。
const originalRenderPage = ctx.renderPage;
// You can consider sharing the same emotion cache between all the SSR requests to speed up performance.
// However, be aware that it can have global side effects.
const cache = createEmotionCache();
const { extractCriticalToChunks } = createEmotionServer(cache);
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) =>
function EnhanceApp(props) {
return <App emotionCache={cache} {...props} />;
},
});
こうしてrenderpageを介して追加した内容をinitialpropsとして抽出。
const initialProps = await Document.getInitialProps(ctx);
この後はemotionとnext.jsの融合の際の何らかの問題を解決するために加えられたもの。この辺りは理解の仕方を聞いた方が良いかもしれない。
// This is important. It prevents emotion to render invalid HTML.
// See https://github.com/mui/material-ui/issues/26561#issuecomment-855286153
const emotionStyles = extractCriticalToChunks(initialProps.html);
const emotionStyleTags = emotionStyles.styles.map((style) => (
<style
data-emotion={`${style.key} ${style.ids.join(' ')}`}
key={style.key}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: style.css }}
/>
));
最終的に返すもの。これはわかる。
return {
...initialProps,
emotionStyleTags,
};
};
一度index.jsの内容を引っこ抜いて他のページでシンプルな形で表示し直す。
next_app_projectからimage画像を引っ張るスクリプトを持ってきた。これで<MyImage fname="image.jpg" size="250" />を挿入するときちんとサイドバーに表示された。
export default function MyImage(props) {
let fname = './' + props.fname
let size = props.size + "px"
return (
<img width={size} border="1"
src={fname} />
)
}
めちゃわかりやすいmuiの説明動画見つけた。