├── .changeset ├── README.md └── config.json ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .npmrc ├── .nuxtrc ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── jest.config.js ├── package.json ├── playground ├── app.vue ├── nuxt.config.ts └── package.json ├── pnpm-lock.yaml ├── renovate.json ├── src ├── module.ts └── runtime │ ├── emotion.client.ts │ └── emotion.server.ts ├── test ├── basic.test.ts └── fixture │ └── nuxt.config.ts ├── tsconfig.json └── yarn.lock /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "restricted", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Common 2 | node_modules 3 | dist 4 | .nuxt 5 | coverage 6 | 7 | # Plugin 8 | lib/plugin.js 9 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["prettier"], 3 | "extends": "@nuxtjs/eslint-config-typescript", 4 | "rules": { 5 | "@typescript-eslint/no-unused-vars": ["off"], 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | ci: 13 | runs-on: ${{ matrix.os }} 14 | 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest] 18 | node: [16] 19 | 20 | steps: 21 | - uses: actions/setup-node@master 22 | with: 23 | node-version: ${{ matrix.node }} 24 | 25 | - name: checkout 26 | uses: actions/checkout@master 27 | 28 | - uses: pnpm/action-setup@v2 29 | name: Install pnpm 30 | id: pnpm-install 31 | with: 32 | version: 7 33 | run_install: false 34 | 35 | - name: Get pnpm store directory 36 | id: pnpm-cache 37 | shell: bash 38 | run: | 39 | echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT 40 | 41 | - uses: actions/cache@v3 42 | name: Setup pnpm cache 43 | with: 44 | path: ${{ steps.pnpm-cache.outputs.STORE_PATH }} 45 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 46 | restore-keys: | 47 | ${{ runner.os }}-pnpm-store- 48 | 49 | - name: Install dependencies 50 | if: steps.cache.outputs.cache-hit != 'true' 51 | run: pnpm install && pnpm dev:prepare 52 | 53 | - name: Lint 54 | run: pnpm lint 55 | 56 | - name: Test 57 | run: pnpm test 58 | 59 | - name: Coverage 60 | uses: codecov/codecov-action@v3 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.iml 3 | .idea 4 | *.log* 5 | .nuxt 6 | .vscode 7 | .DS_Store 8 | coverage 9 | dist 10 | .idea 11 | .output 12 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /.nuxtrc: -------------------------------------------------------------------------------- 1 | imports.autoImport=true 2 | typescript.includeWorkspace=true 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.2 4 | 5 | ### Patch Changes 6 | 7 | - Fix: flatten emotion/css version 8 | 9 | ## 1.0.1 10 | 11 | ### Patch Changes 12 | 13 | - Upgrade emotion packages and add changesets publish workflow 14 | 15 | ## 1.0.0 16 | 17 | ### Major Changes 18 | 19 | - Support Nuxt 3 20 | 21 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 22 | 23 | ## [0.1.0](https://github.com/nuxt-community/emotion-module/compare/v0.0.1...v0.1.0) (2020-12-17) 24 | 25 | ### ⚠ BREAKING CHANGES 26 | 27 | - upgrade emotion to @emotion/css 28 | 29 | ### Features 30 | 31 | - upgrade emotion to @emotion/css ([1b1c02a](https://github.com/nuxt-community/emotion-module/commit/1b1c02ab9289d011987648127c2d819e16399aee)) 32 | 33 | 34 | 35 | ## 0.0.1 (2019-02-09) 36 | 37 | ### Bug Fixes 38 | 39 | - support runtime and buildtime SPA ([8405f50](https://github.com/nuxt-community/emotion-module/commit/8405f50)) 40 | - **module:** set sourceMap and autoLabel based on dev mode ([725196f](https://github.com/nuxt-community/emotion-module/commit/725196f)) 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Nuxt Community 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | emotion 3 |

@nuxtjs/emotion

4 |

5 |

6 | npm version 7 | npm downloads 8 | circle ci 9 | coverage 10 | License 11 |

12 | 13 | > [Emotion](https://emotion.sh) module for [Nuxt.js](https://nuxtjs.org) 14 | 15 | ## Features 16 | 17 | - Server Side Rendering (**SSR**) 18 | - Critical Path CSS with Hydration 19 | - Hot Reloads (**HMR**) 20 | - Style inlining 21 | - Minification 22 | - Dead Code Elimination 23 | - Source Maps 24 | - Contextual Class Names 25 | 26 | [📖 **Release Notes**](./CHANGELOG.md) 27 | 28 | ## Setup 29 | 30 | 1. Add `@nuxtjs/emotion` dependency to your project 31 | 32 | ```bash 33 | yarn add @nuxtjs/emotion # or npm install @nuxtjs/emotion 34 | ``` 35 | 36 | 2. Add `@nuxtjs/emotion` to the `modules` section of `nuxt.config.js` 37 | 38 | ```js 39 | export default { 40 | modules: [ 41 | '@nuxtjs/emotion', 42 | ] 43 | } 44 | ``` 45 | 46 | ## Nuxt 2 47 | Nuxt 2 is supported with `@nuxtjs/emotion@0.1.0`, Documentation is on https://github.com/nuxt-community/emotion-module/tree/v0 and the code on the [`v0`](https://github.com/nuxt-community/emotion-module/tree/v0) branch. 48 | 49 | ## Development 50 | 51 | - Clone this repository 52 | - Install dependencies using `yarn install` or `npm install` 53 | - Start development server using `npm run dev` 54 | 55 | ## License 56 | 57 | [MIT License](./LICENSE) 58 | 59 | Copyright (c) Nuxt Community 60 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: '@nuxt/test-utils' 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nuxtjs/emotion", 3 | "version": "1.0.2", 4 | "description": "The Next Generation of CSS-in-JS for Nuxt.js", 5 | "repository": "nuxt-modules/emotion", 6 | "license": "MIT", 7 | "type": "module", 8 | "exports": { 9 | ".": { 10 | "import": "./dist/module.mjs", 11 | "require": "./dist/module.cjs" 12 | } 13 | }, 14 | "main": "./dist/module.cjs", 15 | "types": "./dist/types.d.ts", 16 | "files": [ 17 | "dist" 18 | ], 19 | "scripts": { 20 | "prepack": "nuxt-module-build", 21 | "dev": "nuxi dev playground", 22 | "dev:build": "nuxi build playground", 23 | "dev:prepare": "nuxt-module-build --stub && nuxi prepare playground", 24 | "lint": "eslint --ext .js,.vue,.ts .", 25 | "test": "vitest" 26 | }, 27 | "dependencies": { 28 | "@emotion/css": "^11.10.6", 29 | "@emotion/server": "^11.10.0", 30 | "@nuxt/kit": "^3.4.2" 31 | }, 32 | "devDependencies": { 33 | "@changesets/cli": "^2.26.1", 34 | "@nuxt/module-builder": "^0.3.0", 35 | "@nuxt/schema": "^3.4.2", 36 | "@nuxt/test-utils": "^3.4.2", 37 | "@nuxtjs/eslint-config-typescript": "^12.0.0", 38 | "@typescript-eslint/eslint-plugin": "^5.59.0", 39 | "eslint": "^8.39.0", 40 | "eslint-plugin-prettier": "^4.2.1", 41 | "eslint-plugin-promise": "^6.1.1", 42 | "nuxt": "^3.4.2", 43 | "prettier": "^2.8.8", 44 | "typescript": "*", 45 | "vitest": "^0.30.1" 46 | }, 47 | "publishConfig": { 48 | "access": "public" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /playground/app.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 52 | -------------------------------------------------------------------------------- /playground/nuxt.config.ts: -------------------------------------------------------------------------------- 1 | import { defineNuxtConfig } from 'nuxt/config' 2 | import emotionModule from '..' 3 | 4 | export default defineNuxtConfig({ 5 | modules: [emotionModule] 6 | }) 7 | -------------------------------------------------------------------------------- /playground/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "nuxt-emotion-playground" 4 | } 5 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@nuxtjs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/module.ts: -------------------------------------------------------------------------------- 1 | import { 2 | defineNuxtModule, 3 | addPlugin, 4 | createResolver, 5 | addServerPlugin 6 | } from '@nuxt/kit' 7 | 8 | declare global { 9 | interface Window { 10 | /** Serialized SSR IDs for emotion */ 11 | $emotionSSRIds: string[]; 12 | } 13 | } 14 | 15 | export default defineNuxtModule({ 16 | meta: { 17 | name: '@nuxtjs/emotion', 18 | configKey: 'emotion', 19 | compatibilty: '>=3.0.0' 20 | }, 21 | setup (_, nuxt) { 22 | // ensure `nitro.plugins` is initialized 23 | nuxt.options.nitro.plugins = nuxt.options.nitro.plugins || [] 24 | 25 | nuxt.hook('nitro:config', (config) => { 26 | // Prevent inlining emotion (+ the crucial css cache!) in dev mode 27 | if (nuxt.options.dev) { 28 | if (config.externals) { 29 | config.externals.external ||= [] 30 | config.externals.external.push('@emotion/server') 31 | } 32 | } 33 | }) 34 | 35 | /** 36 | * Register emotion plugin 37 | */ 38 | const { resolve } = createResolver(import.meta.url) 39 | const runtimeDir = resolve('./runtime') 40 | nuxt.options.build.transpile.push(runtimeDir) 41 | addServerPlugin(resolve(runtimeDir, 'emotion.server')) 42 | addPlugin(resolve(runtimeDir, 'emotion.client')) 43 | } 44 | }) 45 | -------------------------------------------------------------------------------- /src/runtime/emotion.client.ts: -------------------------------------------------------------------------------- 1 | import { hydrate } from '@emotion/css' 2 | import { defineNuxtPlugin } from '#app' 3 | 4 | export default defineNuxtPlugin((_) => { 5 | if (window.$emotionSSRIds) { 6 | const ids = window.$emotionSSRIds 7 | hydrate(ids) 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /src/runtime/emotion.server.ts: -------------------------------------------------------------------------------- 1 | import { extractCritical } from '@emotion/server' 2 | import { NitroApp } from 'nitropack' 3 | 4 | /** 5 | * Why are we declaring types for `defineNitroPlugin`? 6 | * 7 | * It appears that there is no way to import `defineNitroPlugin` from #imports 8 | * without TypeScript screaming. It might be that the `#imports` types are not 9 | * exported at project generation phase with `nuxi` CLI 10 | * 11 | * If this issue can be resolved, then this code can of course be deleted 12 | * and changed to the following: 13 | * 14 | * ```ts 15 | * import { defineNitroPlugin } from '#imports' 16 | * ``` 17 | */ 18 | 19 | export type NitroAppPlugin = (nitro: NitroApp) => void 20 | 21 | export function defineNitroPlugin (def: NitroAppPlugin): NitroAppPlugin { 22 | return def 23 | } 24 | 25 | export default defineNitroPlugin((nitroApp) => { 26 | nitroApp.hooks.hook('render:html', (html) => { 27 | const { ids, css } = extractCritical(html.body) 28 | html.head.push(``) 29 | html.head.push( 30 | `` 33 | ) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /test/basic.test.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { describe, it, expect } from 'vitest' 3 | import { setup, $fetch } from '@nuxt/test-utils' 4 | describe('nust emotion ssr', async () => { 5 | await setup({ 6 | rootDir: fileURLToPath(new URL('../playground', import.meta.url)) 7 | }) 8 | it('renders the index page', async () => { 9 | const html = await $fetch('/') 10 | expect(html).toContain('