[英]NextJs Tailwind build (purge) removes all styling
In my current NextJS project, I am using Tailwind as a CSS framework.在我当前的 NextJS 项目中,我使用 Tailwind 作为 CSS 框架。 When I run
yarn dev
, everything works fine, but whenever I run yarn build
followed by a yarn start
, all of my CSS seems to be purged as the layout of my page is completely different.当我运行
yarn dev
时,一切正常,但每当我运行yarn build
后跟yarn start
,我的所有 CSS 似乎都被清除了,因为我的页面布局完全不同。
My tailwind.config.js file:我的 tailwind.config.js 文件:
/* eslint-disable global-require */
const defaultTheme = require('tailwindcss/defaultTheme');
module.exports = {
purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
darkMode: false, // or 'media' or 'class'
theme: {
screens: {
sm: '640px',
md: '768px',
max_md: { max: '767px' },
lg: '1024px',
xl: '1536px',
},
colors: {
primary: '#f2a53f',
white: '#fff',
},
fontFamily: {
title: ['Dancing Script', 'Times New Roman', 'sans-serif'],
sans: ['Roboto', ...defaultTheme.fontFamily.sans],
},
textShadow: {
default: '1px 1px 3px #000',
},
zIndex: {
1: -1,
},
extend: {
height: {
128: '32rem',
},
margin: {},
},
},
variants: {
extend: {},
},
plugins: [require('tailwindcss-textshadow')],
};
postcss.config.js file: postcss.config.js 文件:
const purgecss = [
'@fullhuman/postcss-purgecss',
{
content: [
'./pages/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}',
],
defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
},
];
module.exports = {
plugins: [
'tailwindcss',
process.env.NODE_ENV === 'production' ? purgecss : undefined,
],
};
_app.tsx: _app.tsx:
import Head from 'next/head';
import { ApolloProvider } from '@apollo/client';
import { AppProps } from 'next/app';
import { useApollo } from '../../apollo/client';
import '../styles/globals.css';
const MyApp = ({ Component, pageProps }: AppProps) => (
<ApolloProvider client={useApollo(pageProps.initialApolloState)}>
<Component {...pageProps} />
</ApolloProvider>
);
export default MyApp;
globals.css:全球.css:
@tailwind base;
@tailwind components;
@tailwind utilities;
@font-face {
font-family: 'Dancing Script';
font-style: medium;
font-weight: 500;
font-display: swap;
src: local('Dancing Script'),
url(/fonts/DancingScript-Medium.tff) format('tff');
}
body {
margin: 0 !important;
}
package.json dependencies: package.json 依赖项:
"dependencies": {
"@apollo/client": "3.3.12",
"@apollo/react-hooks": "4.0.0",
"@contentful/rich-text-react-renderer": "14.1.2",
"@contentful/rich-text-types": "14.1.2",
"apollo-cache-inmemory": "1.6.6",
"apollo-client": "2.6.10",
"apollo-link-http": "1.5.17",
"autoprefixer": "10.2.5",
"clsx": "1.1.1",
"contentful": "8.2.0",
"graphql": "15.5.0",
"graphql-tag": "2.11.0",
"next": "10.0.9",
"next-with-apollo": "5.1.1",
"postcss": "8.2.8",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-icons": "4.2.0",
"tailwindcss": "2.0.4",
"tailwindcss-textshadow": "2.1.3"
},
"devDependencies": {
"@commitlint/cli": "12.0.1",
"@commitlint/config-conventional": "12.0.1",
"@fullhuman/postcss-purgecss": "4.0.3",
"@types/node": "14.14.35",
"@types/react": "17.0.3",
"@types/react-dom": "17.0.2",
"@typescript-eslint/eslint-plugin": "4.18.0",
"@typescript-eslint/parser": "4.18.0",
"add": "2.0.6",
"commitizen": "4.2.3",
"cz-conventional-changelog": "3.3.0",
"eslint": "7.22.0",
"eslint-config-airbnb": "18.2.1",
"eslint-config-prettier": "8.1.0",
"eslint-import-resolver-typescript": "2.4.0",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jsx-a11y": "6.4.1",
"eslint-plugin-prettier": "3.3.1",
"eslint-plugin-react": "7.22.0",
"eslint-plugin-react-hooks": "4.2.0",
"husky": "5.1.3",
"lint-staged": "10.5.4",
"postcss-preset-env": "6.7.0",
"prettier": "2.2.1",
"typescript": "4.2.3",
"yarn": "1.22.10"
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
}
If there is anything that seems off, feel free to let me know.如果有任何问题,请随时告诉我。 I have looked at other issues online but did not find and solution to my problem.
我在网上查看了其他问题,但没有找到并解决我的问题。
Double check the paths in tailwind.config.js
.仔细检查
tailwind.config.js
中的路径。 If your components are not in the components
directory, then you need to update the purge
paths to reflect this.如果您的组件不在
components
目录中,那么您需要更新purge
路径以反映这一点。
I think I see the issue.我想我看到了这个问题。
@fullhuman/postcss-purgecss
has been bundled with tailwindcss since v1.4 or so. @fullhuman/postcss-purgecss
自 v1.4 左右以来已与 tailwindcss 捆绑在一起。 Since it's manually declared in your postcss file as well, it's being executed twice which is wiping all of your styles.由于它也是在您的 postcss 文件中手动声明的,因此它被执行了两次,这将擦除您的所有 styles。 Also the fact that it only wipes your styles in production indicates that it is the culprit as execution of that particular package is dependent on
process.env.NODE_ENV===production
.此外,它仅在生产中擦除您的 styles 的事实表明它是罪魁祸首,因为执行特定的 package 取决于
process.env.NODE_ENV===production
。 Removing it from your postcss file should resolve your issue since it is already being executed under the hood by the tailwindcss bundle.从您的 postcss 文件中删除它应该可以解决您的问题,因为它已经由 tailwindcss 包在后台执行。
Here is my postcss with tailwindcss@2.0.3
for comparison:这是我的 postcss 与
tailwindcss@2.0.3
进行比较:
postcss.config.js
module.exports = {
plugins: [
'postcss-import',
'tailwindcss',
'postcss-nesting',
'postcss-flexbugs-fixes',
[
'postcss-preset-env',
{
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3,
features: {
'custom-properties': false,
'nesting-rules': true
}
}
]
]
};
One other possibility is that you aren't wrapping the paths/file-types targeted for purging within a top-level content
object.另一种可能性是您没有将要清除的路径/文件类型包装在顶级
content
object 中。 From the code provided for your tailwind.config.js
file:从为您的
tailwind.config.js
文件提供的代码中:
module.exports = {
purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
//...
}
Here is my tailwind.config.js
for cross-comparison这是我用于交叉比较的
tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme');
module.exports = {
important: true,
purge: {
content: [
'./components/**/*.{js,ts,jsx,tsx}',
'./pages/**/*.{js,ts,jsx,tsx}'
],
options: {
safelist: {
standard: ['outline-none']
}
}
},
darkMode: 'class',
theme: {
lineClamp: {
1: 1,
2: 2,
3: 3,
4: 4
},
extend: {
zIndex: {
'-10': '-10',
100: '100',
150: '150'
},
maxWidth: {
'9xl': '121rem', // 1936px
'8xl': '96rem' // 1536px
},
screens: {
xs: '375px',
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
'2xl': '1440px',
'3xl': '1920px'
},
transitionDuration: {
0: '0ms',
300: '300ms',
500: '500ms',
700: '700ms',
1000: '1000ms'
},
rotate: {
0: '0deg',
45: '45deg',
90: '90deg',
125: '125deg',
180: '180deg',
270: '270deg',
360: '360deg'
},
fontFamily: {
header: ['goudy-bookletter-1911', 'serif'],
poppins: ['poppins', 'sans-serif'],
somaRoman: ['neue-haas-grotesk-text', 'sans-serif'],
somaDisplay: ['neue-haas-grotesk-display', 'sans-serif'],
sans: ['Inter var', ...defaultTheme.fontFamily.sans]
},
colors: {
'reddit-0': 'var(--reddit-0)',
'reddit-1': 'var(--reddit-1)',
'reddit-2': 'var(--reddit-2)',
'reddit-3': 'var(--reddit-3)',
'reddit-4': 'var(--reddit-4)',
'primary-0': 'var(--primary-0)',
'primary-1': 'var(--primary-1)',
'primary-2': 'var(--primary-2)',
'primary-3': 'var(--primary-3)',
'primary-4': 'var(--primary-4)',
'primary-5': 'var(--primary-5)',
'primary-6': 'var(--primary-6)',
'primary-7': 'var(--primary-7)',
'primary-8': 'var(--primary-8)',
'primary-9': 'var(--primary-9)',
'secondary-0': 'var(--secondary-0)',
'secondary-1': 'var(--secondary-1)',
'secondary-2': 'var(--secondary-2)',
'accents-0': 'var(--accents-0)',
'accents-1': 'var(--accents-1)',
'accents-2': 'var(--accents-2)',
'accents-3': 'var(--accents-3)',
'accents-4': 'var(--accents-4)',
'accents-5': 'var(--accents-5)',
'accents-6': 'var(--accents-6)',
'accents-7': 'var(--accents-7)',
'accents-8': 'var(--accents-8)',
'accents-9': 'var(--accents-9)',
'theme-0': 'var(--theme-0)',
'theme-1': 'var(--theme-1)',
lightBlue: {
0: '#E3F8FF',
100: '#B3ECFF',
200: '#81DEFD',
300: '#5ED0FA',
400: '#40C3F7',
500: '#2BB0ED',
600: '#1992D4',
700: '#127FBF',
800: '#0B69A3',
900: '#035388'
},
cyan: {
0: '#E0FCFF',
100: '#BEF8FD',
200: '#87EAF2',
300: '#54D1DB',
400: '#38BEC9',
500: '#2CB1BC',
600: '#14919B',
700: '#0E7C86',
800: '#0A6C74',
900: '#044E54'
},
rojo: {
0: '#610316',
100: '#8A041A',
200: '#AB091E',
300: '#CF1124',
400: '#E12D39',
500: '#EF4E4E',
600: '#F86A6A',
700: '#FF9B9B',
800: '#FFBDBD',
900: '#FFE3E3'
},
rosado: {
0: '#620042',
100: '#870557',
200: '#A30664',
300: '#BC0A6F',
400: '#DA127D',
500: '#E8368F',
600: '#F364A2',
700: '#FF8CBA',
800: '#FFB8D2',
900: '#FFE3EC'
},
amarillo: {
0: 'hsl(15, 86%, 30%)',
100: 'hsl(22, 82%, 39%)',
200: 'hsl(29, 80%, 44%)',
300: 'hsl(36, 77%, 49%)',
400: 'hsl(42, 87%, 55%)',
500: 'hsl(44, 92%, 63%)',
600: 'hsl(48, 94%, 68%)',
700: 'hsl(48, 95%, 76%)',
800: 'hsl(48, 100%, 88%)',
900: 'hsl(49, 100%, 96%)'
},
verdeAzulado: {
// blueish-green === teal (espanol)
0: 'hsl(170, 97%, 15%)',
100: 'hsl(168, 80%, 23%)',
200: 'hsl(166, 72%, 28%)',
300: 'hsl(164, 71%, 34%)',
400: 'hsl(162, 63%, 41%)',
500: 'hsl(160, 51%, 49%)',
600: 'hsl(158, 58%, 62%)',
700: 'hsl(156, 73%, 74%)',
800: 'hsl(154, 75%, 87%)',
900: 'hsl(152, 68%, 96%)'
},
redditRed: '#FF4500',
redditNav: '#1A1A1B',
redditSearch: '#272729',
redditBG: '#141415'
},
keyframes: {
wiggle: {
'0%, 100%': { transform: 'rotate(-3deg)' },
'50%': { transform: 'rotate(3deg)' }
},
hero: {
transform: 'translate3d(0px, 0px, 0px)'
}
},
animation: {
wiggle: 'wiggle 10s ease-in-out infinite',
hero: 'hero 1s ease-in-out infinite',
slowPing: 'pulse 10s cubic-bezier(0, 0, 0.2, 1) infinite'
},
width: {
82: '20.5rem',
100: '25rem',
200: '50rem',
'8xl': '96rem'
},
height: {
75: '75vh'
},
spacing: {
7: '1.75rem',
14: '3.5rem',
18: '4.5rem',
25: '6.25rem',
26: '6.5rem',
28: '7rem',
44: '11rem',
82: '20.5rem',
100: '25rem',
104: '26rem',
156: '39rem'
},
boxShadow: {
'outline-2': '0 0 0 2px var(--accents-0)',
magical:
'rgba(0, 0, 0, 0.02) 0px 30px 30px, rgba(0, 0, 0, 0.03) 0px 0px 8px, rgba(0, 0, 0, 0.05) 0px 1px 0px',
cardHover:
'0 4px 4.1px rgba(0, 0, 0, 0.012),0 4.9px 5.8px rgba(0, 0, 0, 0.018),0 6.3px 8.4px rgba(0, 0, 0, 0.029),0 8.8px 12.9px rgba(0, 0, 0, 0.05),0 15px 23px rgba(0, 0, 0, 0.11)'
}
},
variants: {
padding: [
'responsive',
'group-hover',
'hover',
'focus',
'even',
'odd',
'first',
'last'
],
textColor: [
'responsive',
'group-hover',
'hover',
'focus',
'even',
'first',
'last',
'odd'
],
backgroundColor: [
'responsive',
'group-hover',
'hover',
'focus',
'even',
'first',
'last',
'odd'
],
display: ['responsive', 'hover', 'group-hover'],
visibility: ['responsive', 'hover', 'group-hover'],
transitionDuration: ['responsive', 'hover', 'group-hover'],
gridColumn: ['responsive', 'hover', 'first', 'odd', 'even'],
extend: {
ringWidth: [
'responsive',
'hover',
'active',
'focus',
'group-hover'
],
ringColor: [
'responsive',
'hover',
'active',
'focus',
'group-hover'
],
fontSize: ['responsive', 'last', 'first', 'hover', 'focus'],
stroke: ['responsive', 'hover', 'focus', 'group-hover'],
fill: ['responsive', 'hover', 'focus', 'group-hover'],
gridTemplateColumns: [
'responsive',
'last',
'first',
'hover',
'focus'
],
animation: [
'responsive',
'hover',
'focus',
'motion-safe',
'motion-reduce'
],
transitionProperty: [
'responsive',
'hover',
'focus',
'motion-safe',
'motion-reduce'
],
transitionDuration: ['responsive', 'hover', 'focus'],
transitionTimingFunction: ['responsive', 'hover', 'focus'],
transitionDelay: ['responsive', 'hover', 'focus'],
scale: [
'responsive',
'hover',
'focus',
'active',
'group-hover'
],
rotate: [
'responsive',
'hover',
'focus',
'active',
'group-hover'
]
}
}
},
plugins: [
require('tailwindcss-line-clamp'),
require('@tailwindcss/typography'),
require('@tailwindcss/forms'),
require('@tailwindcss/aspect-ratio')
]
};
If you're wondering why I use the postcss-import
package before tailwindcss
in my postcss.config.js, it's for separation of concerns and cleaner code.如果您想知道为什么我在
tailwindcss
中的 tailwindcss 之前使用postcss-import
package,它是为了分离关注点和更清晰的代码。 I have a top-level styles
directory containing index.css
, base.css
, utilities.css
, components.css
, and chrome-bug.css
. I have a top-level
styles
directory containing index.css
, base.css
, utilities.css
8CBA22E28EB17B5F5C6AE2A266AZ , components.css
8CBA22E28EB17B5F5C6AE2A266AZ , and chrome-bug.css
. Their contents are as follows:它们的内容如下:
index.css
@import 'tailwindcss/base';
@import './base.css';
@import 'tailwindcss/components';
@import './components.css';
@import 'tailwindcss/utilities';
@import './utilities.css';
components.css
.fit {
min-height: calc(100vh - 88px);
}
utilities.css
#tsparticles {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: 0;
}
.skeleton {
display: block;
width: 100%;
border-radius: 5px;
background-image: linear-gradient(
270deg,
var(--accents-1),
var(--accents-2),
var(--accents-2),
var(--accents-1)
);
background-size: 400% 100%;
animation: loading 8s ease-in-out infinite;
}
@keyframes loading {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
base.css
#__next {
display: flex;
flex-direction: column;
min-height: 100vh;
}
:root {
--reddit-0: hsl(240, 2%, 8%);
--reddit-1: hsl(240, 2%, 10%);
--reddit-2: hsl(240, 3%, 16%);
--reddit-3: hsl(16, 100%, 50%);
--primary-0: hsl(209, 61%, 16%);
--primary-1: hsl(211, 39%, 23%);
--primary-2: hsl(209, 34%, 30%);
--primary-3: hsl(209, 28%, 39%);
--primary-4: hsl(210, 22%, 49%);
--primary-5: hsl(209, 23%, 60%);
--primary-6: hsl(211, 27%, 70%);
--primary-7: hsl(210, 31%, 80%);
--primary-8: hsl(212, 33%, 89%);
--primary-9: hsl(210, 36%, 96%);
--secondary-0: #d7be69;
--secondary-1: #486581;
--secondary-2: #9fb3c8;
--accents-0: hsl(195, 7%, 11%);
--accents-1: hsl(140, 2%, 26%);
--accents-2: hsl(0, 0%, 49%);
--accents-3: hsl(0, 0%, 64%);
--accents-4: hsl(0, 1%, 81%);
--accents-5: hsl(0, 0%, 89%);
--accents-6: hsl(50, 21%, 95%);
--theme-0: hsl(210, 24%, 84%);
--theme-1: hsl(209, 28%, 39%);
@apply overflow-x-hidden;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
/* Remove Safari input shadow on mobile */
textarea,
input:matches([type='email'], [type='number'], [type='password'], [type='search'], [type='tel'], [type='text'], [type='url']) {
-webkit-appearance: none;
}
html {
height: 100%;
box-sizing: border-box;
touch-action: manipulation;
font-feature-settings: 'case' 1, 'rlig' 1, 'calt' 0;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
-moz-osx-font-smoothing: grayscale;
--webkit-text-size-adjust: none;
text-size-adjust: none;
scroll-behavior: smooth;
}
html,
body {
font-family: var(--font-sans);
text-rendering: optimizeLegibility;
::--webkit-font-smoothing: antialiased;
::--moz-osx-font-smoothing: grayscale;
background-color: var(--reddit-0);
color: var(--text-accents-6);
}
body {
position: relative;
min-height: 100%;
margin: 0;
scrollbar-width: none;
scrollbar-color: var(--primary-0) var(--primary-9); /* scroll thumb and track */
}
body::-webkit-scrollbar {
display: thin; /* Hide scrollbar for Chrome, Safari and Opera https://www.w3schools.com/howto/howto_css_hide_scrollbars.asp */
width: 10px;
}
body::-webkit-scrollbar-track {
background: var(--accents-7); /* color of the tracking area */
}
body::-webkit-scrollbar-thumb {
background-color: var(
--secondary-0
); /* color of the scroll thumb */
border-radius: 0px; /* roundness of the scroll thumb */
border: 3px var(--secondary-0); /* creates padding around scroll thumb */
}
a {
-webkit-tap-highlight-color: hsla(0, 0%, 0%, 0);
}
.animated {
--webkit-animation-duration: 1s;
--animation-duration: 1s;
-animation-duration: 1s;
--webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.fadeIn {
-webkit-animation-name: fadeIn;
animation-name: fadeIn;
}
@-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
chrome-bug.css
/**
* Chrome has a bug with transitions onLoad since 2012!
*
* To prevent a "pop" of content, you have to disable all transitions until
* the page is done loading.
*
* https://lab.laukstein.com/bug/input
* https://twitter.com/timer150/status/1345217126680899584
*/
body.loading * {
transition: none !important;
}
The chrome-bug class is conditionally handled via a useEffect
hook in _app.tsx
and is called in the body of _document.tsx
chrome-bug class 通过 _app.tsx 中的
useEffect
挂钩有条件地处理,并在_app.tsx
的主体中_document.tsx
_app.tsx
import '@/styles/index.css';
import '@/styles/chrome-bug.css';
import 'keen-slider/keen-slider.min.css';
import App, {
AppContext,
AppInitialProps,
AppProps,
NextWebVitalsMetric
} from 'next/app';
import { useRouter } from 'next/router';
import { ApolloProvider } from '@apollo/client';
import { useEffect, FC } from 'react';
import {
useApollo,
initializeApollo,
addApolloState
} from '@/lib/apollo';
import * as gtag from '@/lib/analytics';
import { MediaContextProvider } from '@/lib/artsy-fresnel';
import { Head } from '@/components/Head';
import { GTagPageview } from '@/types/analytics';
// import { AppLayout } from '@/components/Layout';
import {
DynamicNavQuery,
DynamicNavQueryVariables,
DynamicNavDocument,
MenuNodeIdTypeEnum
} from '@/graphql/generated/graphql';
const Noop: FC = ({ children }) => <>{children}</>;
function NextApp({
Component,
pageProps: { ...pageProps }
}: AppProps<typeof NextApp.getInitialProps>) {
const apolloClient = useApollo(pageProps);
const LayoutNoop = (Component as any).LayoutNoop || Noop;
const router = useRouter();
useEffect(() => {
document.body.classList?.remove('loading');
}, []);
useEffect(() => {
const handleRouteChange = (url: GTagPageview) => {
gtag.pageview(url);
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => {
router.events.off('routeChangeComplete', handleRouteChange);
};
}, [router.events]);
return (
<>
<Head />
<ApolloProvider client={apolloClient}>
<MediaContextProvider>
<LayoutNoop pageProps={pageProps}>
<Component {...pageProps} />
</LayoutNoop>
</MediaContextProvider>
</ApolloProvider>
</>
);
}
NextApp.getInitialProps = async (
appContext: AppContext
): Promise<AppInitialProps> => {
const pageProps = await App.getInitialProps(appContext);
const graphqlClient = initializeApollo();
const dynamicNav = await graphqlClient.query<
DynamicNavQuery,
DynamicNavQueryVariables
>({
query: DynamicNavDocument,
variables: {
idHead: 'Header',
idTypeHead: MenuNodeIdTypeEnum.Name,
idFoot: 'Footer',
idTypeFoot: MenuNodeIdTypeEnum.Name
}
});
return addApolloState(graphqlClient, {
pageProps: {
...pageProps.pageProps,
Header: dynamicNav.data.Header,
Footer: dynamicNav.data.Footer
}
});
};
export function reportWebVitals(metric: NextWebVitalsMetric) {
console.debug('vital: ', metric);
}
export default NextApp;
_document.tsx
import Document, {
Head,
Html,
Main,
NextScript,
DocumentContext
} from 'next/document';
import { mediaStyles } from '@/lib/artsy-fresnel';
const GA_TRACKING_ID = 'G-RJQZB1C7TR';
class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}
render() {
return (
<Html lang='en-US'>
<Head>
<meta charSet='utf-8' />
<link
rel='stylesheet'
href='https://rsms.me/inter/inter.css'
/>
<link rel='shortcut icon' href='/assets/favicon.ico' />
<style
type='text/css'
dangerouslySetInnerHTML={{ __html: mediaStyles }}
/>
<script
async
src={`https://www.googletagmanager.com/gtag/js?id=${GA_TRACKING_ID}`}
/>
<script
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_TRACKING_ID}', {
page_path: window.location.pathname,
});
`
}}
/>
</Head>
<body className='loading'>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
For the sake of thoroughness, here is my package.json
为了彻底起见,这里是我的
package.json
{
"name": "clean-fade",
"version": "1.0.0",
"main": "index.js",
"repository": "git@gitlab.com:windy-city-devs-llc/clean-fade.git",
"author": "Andrew Ross <andrew.simpson.ross@gmail.com>",
"license": "MIT",
"scripts": {
"test": "jest",
"test-all": "yarn lint && yarn type-check && yarn test",
"codegen": "graphql-codegen --config codegen.yml -r dotenv/config",
"dev": "next -p 5005",
"prod:build": "yarn codegen && yarn build",
"dev:debug": "cross-env NODE_OPTIONS='--inspect' next dev",
"build": "next build",
"analyze": "cross-env ANALYZE=true yarn build",
"find:unused": "next-unused",
"tsconfig:effective": "tsc --showConfig",
"pretty:quick": "yarn pretty-quick --staged",
"prepare": "husky install",
"lint": "eslint . --ext ts --ext tsx --ext js",
"format": "prettier --write .",
"type-check": "tsc --pretty --noEmit"
},
"lint-staged": {
"*.@(ts|tsx)": [
"yarn lint",
"yarn format"
]
},
"next-unused": {
"alias": {
"@/components/*": [
"components/*"
],
"@/config/*": [
"config/*"
],
"@/graphql/*": [
"graphql/*"
],
"@/lib/*": [
"lib/*"
],
"@/pages/*": [
"pages/*"
],
"@/scripts/*": [
"scripts/*"
],
"@/styles/*": [
"styles/*"
],
"@/test/*": [
"test/*"
],
"@/types/*": [
"types/*"
]
},
"debug": true,
"include": [
"components",
"lib",
"pages"
],
"exclude": [],
"entrypoints": [
"pages"
]
},
"dependencies": {
"@apollo/client": "^3.3.12",
"@artsy/fresnel": "^1.3.1",
"@headlessui/react": "^0.3.1",
"@reach/portal": "^0.13.2",
"body-scroll-lock": "^3.1.5",
"classnames": "^2.2.6",
"date-fns": "^2.19.0",
"graphql": "^15.5.0",
"html-react-parser": "^1.2.4",
"isomorphic-unfetch": "^3.1.0",
"js-cookie": "^2.2.1",
"keen-slider": "^5.4.0",
"lodash.random": "^3.2.0",
"lodash.throttle": "^4.1.1",
"next": "^10.0.9",
"next-seo": "^4.20.0",
"next-themes": "^0.0.12",
"preact": "^10.5.13",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-intersection-observer": "^8.31.0",
"react-markdown": "^5.0.3",
"react-merge-refs": "^1.1.0",
"react-tsparticles": "^1.20.1",
"remark-gfm": "^1.0.0",
"swr": "^0.5.3",
"tabbable": "^5.1.6"
},
"devDependencies": {
"@babel/core": "^7.13.10",
"@graphql-codegen/cli": "^1.21.3",
"@graphql-codegen/import-types-preset": "^1.18.1",
"@graphql-codegen/introspection": "^1.18.1",
"@graphql-codegen/near-operation-file-preset": "^1.17.13",
"@graphql-codegen/schema-ast": "^1.18.1",
"@graphql-codegen/typescript": "^1.21.1",
"@graphql-codegen/typescript-operations": "^1.17.15",
"@graphql-codegen/typescript-react-apollo": "2.1.1",
"@next/bundle-analyzer": "^10.0.9",
"@tailwindcss/aspect-ratio": "^0.2.0",
"@tailwindcss/forms": "^0.2.1",
"@tailwindcss/typography": "^0.4.0",
"@testing-library/dom": "^7.30.0",
"@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.8.3",
"@types/body-scroll-lock": "^2.6.1",
"@types/classnames": "^2.2.11",
"@types/gtag.js": "^0.0.4",
"@types/jest": "^26.0.20",
"@types/js-cookie": "^2.2.6",
"@types/lodash.random": "^3.2.6",
"@types/lodash.throttle": "^4.1.6",
"@types/node": "^14.14.35",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.2",
"@types/react-test-renderer": "^17.0.1",
"@types/tabbable": "^3.1.0",
"@typescript-eslint/eslint-plugin": "^4.18.0",
"@typescript-eslint/parser": "^4.18.0",
"autoprefixer": "^10.2.5",
"babel-jest": "^26.6.3",
"cross-env": "^7.0.3",
"dotenv": "^8.2.0",
"dotenv-cli": "^4.0.0",
"eslint": "^7.22.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-react": "^7.22.0",
"globby": "^11.0.2",
"husky": "^5.1.3",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.6.3",
"jest-watch-typeahead": "^0.6.1",
"lint-staged": "^10.5.4",
"next-page-tester": "^0.24.0",
"next-unused": "^0.0.3",
"postcss": "^8.2.8",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-import": "^14.0.0",
"postcss-preset-env": "^6.7.0",
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.2.1",
"pretty-quick": "^3.1.0",
"react-test-renderer": "^17.0.1",
"stylelint": "^13.12.0",
"stylelint-config-recommended": "^4.0.0",
"tailwindcss": "^2.0.3",
"tailwindcss-line-clamp": "^1.0.5",
"ts-jest": "^26.5.3",
"typescript": "^4.2.3",
"yaml-loader": "^0.6.0"
}
}
yarn add -D tailwindcss
npx tailwindcss init
module.exports = {
content: [
'./pages/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}'
],
theme: {
extend: {},
},
plugins: [],
}
yarn add @fullhuman/postcss-purgecss postcss-preset-env
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
'@fullhuman/postcss-purgecss': {
content: [
'./pages/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}'
],
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
},
'postcss-preset-env': {}
},
}
After that try adding a classname that you intentionally won't use and try to build for production and test from coverage tab that this classname is not loaded within source file之后尝试添加一个您故意不使用的类名,并尝试从覆盖选项卡构建生产和测试该类名未加载到源文件中
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.