惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threatpost
Project Zero
Project Zero
Know Your Adversary
Know Your Adversary
T
The Exploit Database - CXSecurity.com
P
Palo Alto Networks Blog
T
Tenable Blog
Scott Helme
Scott Helme
T
Tor Project blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
NISL@THU
NISL@THU
Cisco Talos Blog
Cisco Talos Blog
Security Latest
Security Latest
Simon Willison's Weblog
Simon Willison's Weblog
S
Securelist
Help Net Security
Help Net Security
Google DeepMind News
Google DeepMind News
Cloudbric
Cloudbric
C
Check Point Blog
Jina AI
Jina AI
Webroot Blog
Webroot Blog
量子位
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
P
Privacy & Cybersecurity Law Blog
罗磊的独立博客
H
Heimdal Security Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
人人都是产品经理
人人都是产品经理
N
News and Events Feed by Topic
www.infosecurity-magazine.com
www.infosecurity-magazine.com
宝玉的分享
宝玉的分享
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
LINUX DO - 热门话题
The GitHub Blog
The GitHub Blog
T
Troy Hunt's Blog
PCI Perspectives
PCI Perspectives
Vercel News
Vercel News
N
News | PayPal Newsroom
A
Arctic Wolf
T
The Blog of Author Tim Ferriss
博客园 - 司徒正美
博客园 - 叶小钗
Y
Y Combinator Blog
V
V2EX
美团技术团队
O
OpenAI News
Microsoft Security Blog
Microsoft Security Blog
AWS News Blog
AWS News Blog

GeekPlux

一代人的博客,一代人的青春注脚 那些年我打过的日结工 来美国的两年后 2023 一蓑烟雨 在美国拥有一辆 Tesla 的成本 我的 Workspaces 十年进化史 How to Sync Logseq Plugins, Themes and Settings Across Multiple Devices Setting Up Umami as Your Google Analytics Alternative: A Step-by-Step Guide 迁移豆瓣读书记录到 goodreads Enhance Your Internet Privacy in 2023 Refactor your blog comments system with Webmention.io 来美国之后,如何快速安顿下来 Three Levels of Information Perception 疫情三年 与人聊天的美好 我获取信息的方法 2022 版 我是如何学会编程的 Legacy code best practice: how to take over an existing project smoothly 2020 恍如隔世 接外包的一些坑和小技巧 论交友 往返香港隔离指南 即将失明,还能继续做程序员吗 小谈我对新技术的态度 远程工作如何提高效率 复式记账、财报、量化与图论 我为什么从阿里巴巴离职 2019 柳暗花明 投资被动型指数基金正在造成下一次金融泡沫? 三种主流的网赚套利,躺着赚钱? 色盲的世界 我是如何管理 21 张信用卡的 薅羊毛的最大意义:保持对规则的敏感度 来香港的两个月 数据可视化技术实现的关键点 如何找到时薪 80 美元的远程工作(二) 如何找到时薪 80 美元的远程工作(一) 如何打造真正的简历 浅思图数据可视化 舍本逐末的学习方式 给想转行作程序员的人泼一盆冷水 算法优化人生之 —— 调度算法 杭州最适合闲来溜达的几条路线 2018 平淡无奇 突闻金庸先生逝世有感 十年博客折腾历史 数据可视化之 Sankey 桑基图的实现 研究生生涯总结 Web 前端中的增强现实(AR)开发技术 参加 Google Summer of Code 的体验 netjsongraph.js – Google Summer of Code (GSoC) 2017 summary 如何在 GitHub 上获得数百 stars Markvis - 在 markdown 中生成可视化图表 D3 force layout and WebGL integration 文本数据可视化(下)——一图胜千言 文本数据可视化(上)——从 Wordle 谈起 我获取信息的渠道 数据可视化基础——视觉编码 数据可视化基础——数据模型 数据可视化基础——可视化流程 为什么要用 Emacs Vega-Lite: A Grammar of Interactive Graphics 如何阅读一篇学术论文 超过十个人的微信群根本没有价值 毕业后的两年 建立索引式的学习方法 为什么我喜欢写代码 为什么文章写得好的人都很厉害 人总要有点盲目的自信 如何管理好自己的密码 Backbone View 之间通信的三种方式 Vim - 适合自己的,才是最好的 轻松玩转 Ukulele 告别社交网络有多难 双拼学习记 CoffeeScript 编码风格指南(译) CoffeeScript 笔记 CSS 最核心的几个概念 响应式设计简易指南(译) 初识 TDD Collapsing margins——合并的外边距 菜鸟级 Mac 配置(二) 菜鸟级 Mac 配置(一) CSS 编写原则 Goodbye,我的大学 如何新建一个 Cocos2d-x 项目 Windows8.1 下 Cocos2d-x 环境搭建 Android 开发如何入门 如何绑定独立域名 写博客就用 FarBox 尝试改变微信公众账号消息的推送方式 情似流水 操作系统总结——存储器管理 操作系统总结——处理机管理 操作系统总结——引论 C++指针与引用小结 该不该制定计划 幸福,是一种能力 弱冠,瞎扯 别当回事儿
How to use tailwindcss with AMP in a Next.js project
GeekPlux · 2020-03-25 · via GeekPlux

How to use tailwindcss with AMP in a Next.js project

Recently, I was refactoring my blog using Next.js by a whim. There are 3 tech stacks I would use:

  • Next.js , a popular React framework with SSG, SSR support naturally
  • Tailwindcss , a low-level CSS framework with the utility-first concept.
  • AMP , an HTML framework developed by Google to make your website fast and loading smoothly.

However, There are so many restrictions in AMP for performance issues. At the beginning of the project, I found this issue, which means you can NOT add a global CSS as Next.js documented. So this article may be a guide for how to use tailwindcss with AMP in a Next.js project.

Step 1: How to add style in AMP

First, we are supposed to know how to add style for a page in AMP. After look up their official documents, there are only two ways to style your site:

React JSX syntax lets you add CSS inline intuitively, written as attributes and passed to elements. But it's pain to write pseudo-classes, add prefix and maintain. Besides, tailwindcss has already listed in our armoury, so I have to choose another method.

Define CSS within the <style amp-custom> tag, then add the class name to where you wanna style. The only one thing is different from your usual CSS writing is to write it in the <head> <style> tag.

<!doctype html>
  <head>
    ...
    <style amp-custom>
      /* any custom styles go here. */
      amp-img.grey-placeholder {
        background-color: grey;
      }
    </style>
    ...
  </head>
  <body>
  	<amp-img
    	class="grey-placeholder"
    	src="https://..."
    	srcset="..."
    	width="500"
    	height="300"
    	layout="responsive">
    </amp-img>
  </body>

JJ Kasper provided a way to implement this in Next.js: to overwrite _document.

// pages/_document.js
export default class MyDocument extends Document {
  static async getInitialProps (ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    return {
      ...initialProps,
      styles: (
        <>
          {initialProps.styles}
          <style dangerouslySetInnerHTML={{
            __html: `body{ background: orange; }`
          }} />
        </>
      )
    }
  }
}

So the next step is how to add tailwind CSS as a string into <style> tag.

Step 2: How to add a CSS file as String into style tag

This step is too simple to just add a loader the Webpack config in next.config.js. raw-loader allows importing files as a String, you could add it following Webpack customing doc:

// next.config.js
module.exports = {
  webpack: (config) => {
    config.module.rules.push(
      {
        test: /\.css$/,
        use: 'raw-loader'
      }
    )
    return config
  },
}

Then download the tailwind.min.css to your styles folder at root directory, try to import it in pages/_document.js

// pages/_document.js
import tailwindcss from '!raw-loader!../styles/tailwind.min.css';

That's it! But when you run next start again after these steps, you would encounter a warning (if your pages are set to AMP):

[ warn ]  Amp Validation

/  error  The author stylesheet specified in tag 'style amp-custom (transformed)' is too long - document contains 725366 bytes whereas the limit is 75000 bytes.  https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml#maximum-size

Don't worry, we all know warning is not error. We can ignore this warning message during development until you wanna build a production version.

Step 3 How to build and deploy

Not only is it because of AMP validation error, but to add entire tailwindcss package into the final bundle is too big, so we need to process tailwindcss, leaving only the classes we actually use.

If your project was created by an official example, you would see the postcss.config.js under root folder, and tailwindcss was imported in styles/index.css

/* styles/index.css */

/* purgecss start ignore */
@tailwind base;
@tailwind components;
/* purgecss end ignore */
@tailwind utilities;

Next.js compiles CSS using PostCSS, so you can just create a postcss.config.js without other config then it works. And as you know, postcss.config.js also is able to used by PostCSS CLI.

You need to add 2 steps before building process:

  • Compile a output.css file to styles folder.
  • Import styles/output.css as String in pages/_document.js.

So first, let's tweak postcss.config.js for CLI using because of require() function syntax.

// postcss.config.js
const purgecssOption = {
  // Specify the paths to all of the template files in your project
  content: [
    './pages/**/*.{js,jsx,ts,tsx}',
    './components/**/*.{js,jsx,ts,tsx}'
  ],

  // Include any special characters you're using in this regular expression
  defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
};

module.exports = {
  plugins:
    process.env.CSS_ENV === 'build'
      ? [
          require('tailwindcss'),
          require('@fullhuman/postcss-purgecss')(purgecssOption),
          require('postcss-preset-env'),
          require('cssnano')({
            preset: 'default'
          })
        ]
      : [
          'tailwindcss',
          process.env.NODE_ENV === 'production'
            ? ['@fullhuman/postcss-purgecss', purgecssOption]
            : undefined,
          'postcss-preset-env'
        ]
};

Please notice a env variable called CSS_ENV, it is going to use in future steps.

Second, importing styles/output.css:

// pages/_document.js
import outputcss from '!raw-loader!../styles/output.css';
import tailwindcss from '!raw-loader!../styles/tailwind.min.css';
const cssFile = process.env.NODE_ENV === 'production' ? outputcss : tailwindcss;

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);

    return {
      ...initialProps,
      styles: (
        <>
          <style
            dangerouslySetInnerHTML={{
              __html: cssFile
            }}
          />
          {initialProps.styles}
        </>
      )
    };
  }
  render() {...}
}

When you run command here:

CSS_ENV=build postcss styles/index.css --config postcss.config.js -o styles/output.css

you would see output.css is generated. That's convenient if you add this line to your package.json scripts.

// package.json
  "scripts": {
    "dev": "next",
    "build": "yarn build-css && next build",
    "build-css": "CSS_ENV=build postcss styles/index.css --config postcss.config.js -o styles/output.css",
    ...
  }

Then you run yarn build or npm run build every time, it would compile CSS automatically.

// ls -al styles
-rw-r--r--  1 geekplux  staff   7.7K Mar 24 01:54 output.css
-rw-r--r--@ 1 geekplux  staff   694K Mar 23 06:48 tailwind.min.css

After completing all the steps, you can now use tailwindcss well in both development and production environments.

Summary

OK finally, in a summary, you should NOT use tailwind in your Next.js project, because when you define a custom PostCSS configuration file, Next.js completely disables the built-in default behavior......it's a joke.