feat(build): use __DEV__ to control development mode (#789)

* feat(build): use __DEV__ to control development mode

* fix workflow

* missing env in systemjs build
This commit is contained in:
Daishi Kato 2022-02-10 08:45:43 +09:00 committed by GitHub
parent e90e8bc7b6
commit 5b938fbbff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 241 additions and 33 deletions

View File

@ -0,0 +1,57 @@
name: Test Multiple Builds
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize]
jobs:
test_matrix:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
build: [cjs, umd] # [cjs, esm, umd, system]
env: [development, production]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '12'
cache: yarn
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- run: yarn install --frozen-lockfile --check-files
- run: yarn build
- name: Patch for DEV-ONLY
if: ${{ matrix.env == 'development' }}
run: |
sed -i~ "s/it[a-zA-Z]*('\[PRD-ONLY\]/it.skip('/" tests/*.tsx
- name: Patch for PRD-ONLY
if: ${{ matrix.env == 'production' }}
run: |
sed -i~ "s/it[a-zA-Z]*('\[DEV-ONLY\]/it.skip('/" tests/*.tsx
- name: Patch for CJS
if: ${{ matrix.build == 'cjs' }}
run: |
sed -i~ "s/<rootDir>\/src\(.*\)\.ts/<rootDir>\/dist\1.js/" package.json
- name: Patch for ESM
if: ${{ matrix.build == 'esm' }}
run: |
sed -i~ "s/<rootDir>\/src\(.*\)\.ts/<rootDir>\/dist\/esm\1.js" package.json
sed -i~ "1s/^/import.meta.env=import.meta.env||{};import.meta.env.MODE='${NODE_ENV}';/" tests/*.tsx
env:
NODE_ENV: ${{ matrix.env }}
- name: Patch for UMD/SystemJS
if: ${{ matrix.build == 'umd' || matrix.build == 'system' }}
run: |
sed -i~ "s/<rootDir>\/src\(.*\)\.ts/<rootDir>\/dist\/${BUILD}\1.${NODE_ENV}.js/" package.json
env:
BUILD: ${{ matrix.build }}
NODE_ENV: ${{ matrix.env }}
- name: Test ${{ matrix.build }} ${{ matrix.env }}
run: |
cat package.json
yarn test:ci
env:
NODE_ENV: ${{ matrix.env }}

View File

@ -44,7 +44,7 @@
"sideEffects": false,
"scripts": {
"prebuild": "shx rm -rf dist",
"build": "concurrently 'yarn:build:*'",
"build": "concurrently -m 8 'yarn:build:*'",
"build:base": "rollup -c",
"build:vanilla": "rollup -c --config-vanilla",
"build:middleware": "rollup -c --config-middleware",
@ -106,6 +106,9 @@
"@swc/jest"
]
},
"globals": {
"__DEV__": true
},
"moduleNameMapper": {
"^zustand$": "<rootDir>/src/index.ts",
"^zustand/(.*)$": "<rootDir>/src/$1.ts"
@ -136,6 +139,7 @@
"@babel/preset-env": "^7.16.5",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-node-resolve": "^13.1.1",
"@rollup/plugin-replace": "^3.0.1",
"@rollup/plugin-typescript": "^8.3.0",
"@swc/core": "^1.2.122",
"@swc/jest": "^0.2.15",
@ -165,6 +169,7 @@
"react-dom": "^17.0.2",
"rollup": "^2.62.0",
"rollup-plugin-esbuild": "^4.7.2",
"rollup-plugin-terser": "^7.0.2",
"shx": "^0.3.3",
"typescript": "^4.5.4"
},

View File

@ -1,8 +1,10 @@
import path from 'path'
import babelPlugin from '@rollup/plugin-babel'
import resolve from '@rollup/plugin-node-resolve'
import replace from '@rollup/plugin-replace'
import typescript from '@rollup/plugin-typescript'
import esbuild from 'rollup-plugin-esbuild'
import { terser } from 'rollup-plugin-terser'
const createBabelConfig = require('./babel.config')
const extensions = ['.js', '.ts', '.tsx']
@ -21,9 +23,9 @@ function getBabelOptions(targets) {
}
}
function getEsbuild(target) {
function getEsbuild(target, env = 'development') {
return esbuild({
minify: false,
minify: env === 'production',
target,
tsconfig: path.resolve('./tsconfig.json'),
})
@ -54,49 +56,79 @@ function createESMConfig(input, output) {
{ file: `${output}.mjs`, format: 'esm' },
],
external,
plugins: [resolve({ extensions }), getEsbuild('node12')],
plugins: [
resolve({ extensions }),
replace({
__DEV__: '(import.meta.env&&import.meta.env.MODE)!=="production"',
preventAssignment: true,
}),
getEsbuild('node12'),
],
}
}
function createCommonJSConfig(input, output) {
return {
input,
output: { file: output, format: 'cjs', exports: 'named' },
output: { file: `${output}.js`, format: 'cjs', exports: 'named' },
external,
plugins: [
resolve({ extensions }),
replace({
__DEV__: 'process.env.NODE_ENV!=="production"',
preventAssignment: true,
}),
babelPlugin(getBabelOptions({ ie: 11 })),
],
}
}
function createUMDConfig(input, output) {
function createUMDConfig(input, output, env) {
const c = output.split('/').pop()
return {
input,
output: {
file: output,
file: `${output}.${env}.js`,
format: 'umd',
exports: 'named',
name: 'zustand',
name:
c === 'index'
? 'zustand'
: `zustand${c.slice(0, 1).toUpperCase()}${c.slice(1)}`,
globals: {
react: 'React',
},
},
external,
plugins: [
resolve({ extensions }),
replace({
__DEV__: env !== 'production' ? 'true' : 'false',
preventAssignment: true,
}),
babelPlugin(getBabelOptions({ ie: 11 })),
...(env === 'production' ? [terser()] : []),
],
}
}
function createSystemConfig(input, output) {
function createSystemConfig(input, output, env) {
return {
input,
output: {
file: output,
file: `${output}.${env}.js`,
format: 'system',
exports: 'named',
},
external,
plugins: [resolve({ extensions }), getEsbuild('node12')],
plugins: [
resolve({ extensions }),
replace({
__DEV__: env !== 'production' ? 'true' : 'false',
preventAssignment: true,
}),
getEsbuild('node12', env),
],
}
}
@ -104,18 +136,16 @@ export default function (args) {
let c = Object.keys(args).find((key) => key.startsWith('config-'))
if (c) {
c = c.slice('config-'.length).replace(/_/g, '/')
return [
createCommonJSConfig(`src/${c}.ts`, `dist/${c}.js`),
createESMConfig(`src/${c}.ts`, `dist/esm/${c}`),
createUMDConfig(`src/${c}.ts`, `dist/umd/${c}.js`),
createSystemConfig(`src/${c}.ts`, `dist/system/${c}.js`),
]
} else {
c = 'index'
}
return [
createDeclarationConfig('src/index.ts', 'dist'),
createCommonJSConfig('src/index.ts', 'dist/index.js'),
createESMConfig('src/index.ts', 'dist/esm/index'),
createUMDConfig('src/index.ts', 'dist/umd/index.js'),
createSystemConfig('src/index.ts', 'dist/system/index.js'),
...(c === 'index' ? [createDeclarationConfig(`src/${c}.ts`, 'dist')] : []),
createCommonJSConfig(`src/${c}.ts`, `dist/${c}`),
createESMConfig(`src/${c}.ts`, `dist/esm/${c}`),
createUMDConfig(`src/${c}.ts`, `dist/umd/${c}`, 'development'),
createUMDConfig(`src/${c}.ts`, `dist/umd/${c}`, 'production'),
createSystemConfig(`src/${c}.ts`, `dist/system/${c}`, 'development'),
createSystemConfig(`src/${c}.ts`, `dist/system/${c}`, 'production'),
]
}

View File

@ -176,10 +176,7 @@ export function devtools<
}
if (!extensionConnector) {
if (
process.env.NODE_ENV === 'development' &&
typeof window !== 'undefined'
) {
if (__DEV__ && typeof window !== 'undefined') {
console.warn(
'[zustand devtools middleware] Please install/enable Redux devtools extension'
)

2
src/types.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
// eslint-disable-next-line no-var
declare var __DEV__: boolean

View File

@ -35,22 +35,25 @@ it('connects to the extension by passing the options and initializes', () => {
})
describe('If there is no extension installed...', () => {
let savedDEV: boolean
beforeAll(() => {
savedDEV = __DEV__
;(window as any).__REDUX_DEVTOOLS_EXTENSION__ = undefined
})
afterAll(() => {
__DEV__ = savedDEV
;(window as any).__REDUX_DEVTOOLS_EXTENSION__ = extensionConnector
})
it('does not throw', () => {
__DEV__ = false
expect(() => {
create(devtools(() => ({ count: 0 })))
}).not.toThrow()
})
it('warns in dev env', () => {
const originalNodeEnv = process.env.NODE_ENV
process.env.NODE_ENV = 'development'
it('[DEV-ONLY] warns in dev env', () => {
__DEV__ = true
const originalConsoleWarn = console.warn
console.warn = jest.fn()
@ -59,11 +62,11 @@ describe('If there is no extension installed...', () => {
'[zustand devtools middleware] Please install/enable Redux devtools extension'
)
process.env.NODE_ENV = originalNodeEnv
console.warn = originalConsoleWarn
})
it('does not warn if not in dev env', () => {
it('[PRD-ONLY] does not warn if not in dev env', () => {
__DEV__ = false
const consoleWarn = jest.spyOn(console, 'warn')
create(devtools(() => ({ count: 0 })))

View File

@ -71,6 +71,14 @@ describe('counter state spec (no middleware)', () => {
})
describe('counter state spec (single middleware)', () => {
let savedDEV: boolean
beforeEach(() => {
savedDEV = __DEV__
})
afterEach(() => {
__DEV__ = savedDEV
})
it('immer', () => {
const useStore = create<CounterState>(
immer((set, get) => ({
@ -118,6 +126,7 @@ describe('counter state spec (single middleware)', () => {
})
it('devtools', () => {
__DEV__ = false
const useStore = create<
CounterState,
SetState<CounterState>,
@ -243,7 +252,16 @@ describe('counter state spec (single middleware)', () => {
})
describe('counter state spec (double middleware)', () => {
let savedDEV: boolean
beforeEach(() => {
savedDEV = __DEV__
})
afterEach(() => {
__DEV__ = savedDEV
})
it('devtools & immer', () => {
__DEV__ = false
const useStore = create<
CounterState,
SetState<CounterState>,
@ -275,6 +293,7 @@ describe('counter state spec (double middleware)', () => {
})
it('devtools & redux', () => {
__DEV__ = false
const useStore = create(
devtools(
redux<{ count: number }, { type: 'INC' }>(
@ -303,6 +322,7 @@ describe('counter state spec (double middleware)', () => {
})
it('devtools & combine', () => {
__DEV__ = false
const useStore = create(
devtools(
combine({ count: 1 }, (set, get) => ({
@ -349,6 +369,7 @@ describe('counter state spec (double middleware)', () => {
})
it('devtools & subscribeWithSelector', () => {
__DEV__ = false
const useStore = create<
CounterState,
SetState<CounterState>,
@ -382,6 +403,7 @@ describe('counter state spec (double middleware)', () => {
})
it('devtools & persist', () => {
__DEV__ = false
const useStore = create<
CounterState,
SetState<CounterState>,
@ -415,7 +437,16 @@ describe('counter state spec (double middleware)', () => {
})
describe('counter state spec (triple middleware)', () => {
let savedDEV: boolean
beforeEach(() => {
savedDEV = __DEV__
})
afterEach(() => {
__DEV__ = savedDEV
})
it('devtools & persist & immer', () => {
__DEV__ = false
const useStore = create<
CounterState,
SetState<CounterState>,
@ -451,6 +482,7 @@ describe('counter state spec (triple middleware)', () => {
})
it('devtools & subscribeWithSelector & combine', () => {
__DEV__ = false
const useStore = create(
devtools(
subscribeWithSelector(
@ -479,6 +511,7 @@ describe('counter state spec (triple middleware)', () => {
})
it('devtools & subscribeWithSelector & persist', () => {
__DEV__ = false
const useStore = create<
CounterState,
SetState<CounterState>,
@ -520,7 +553,16 @@ describe('counter state spec (triple middleware)', () => {
})
describe('counter state spec (quadruple middleware)', () => {
let savedDEV: boolean
beforeEach(() => {
savedDEV = __DEV__
})
afterEach(() => {
__DEV__ = savedDEV
})
it('devtools & subscribeWithSelector & persist & immer (#616)', () => {
__DEV__ = false
const useStore = create<
CounterState,
SetState<CounterState>,

View File

@ -1233,6 +1233,14 @@
is-module "^1.0.0"
resolve "^1.19.0"
"@rollup/plugin-replace@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-3.0.1.tgz#f774550f482091719e52e9f14f67ffc0046a883d"
integrity sha512-989J5oRzf3mm0pO/0djTijdfEh9U3n63BIXN5X7T4U9BP+fN4oxQ6DvDuBvFaHA6scaHQRclqmKQEkBhB7k7Hg==
dependencies:
"@rollup/pluginutils" "^3.1.0"
magic-string "^0.25.7"
"@rollup/plugin-typescript@^8.3.0":
version "8.3.0"
resolved "https://registry.yarnpkg.com/@rollup/plugin-typescript/-/plugin-typescript-8.3.0.tgz#bc1077fa5897b980fc27e376c4e377882c63e68b"
@ -2064,6 +2072,11 @@ combined-stream@^1.0.8:
dependencies:
delayed-stream "~1.0.0"
commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
commander@^8.3.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
@ -3637,6 +3650,15 @@ jest-watcher@^27.4.2:
jest-util "^27.4.2"
string-length "^4.0.1"
jest-worker@^26.2.1:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
supports-color "^7.0.0"
jest-worker@^27.4.5:
version "27.4.5"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.5.tgz#d696e3e46ae0f24cff3fa7195ffba22889262242"
@ -3888,6 +3910,13 @@ lz-string@^1.4.4:
resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26"
integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=
magic-string@^0.25.7:
version "0.25.7"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051"
integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==
dependencies:
sourcemap-codec "^1.4.4"
make-dir@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@ -4279,6 +4308,13 @@ queue-microtask@^1.2.2:
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
dependencies:
safe-buffer "^5.1.0"
react-dom@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
@ -4451,6 +4487,16 @@ rollup-plugin-esbuild@^4.7.2:
joycon "^3.0.1"
jsonc-parser "^3.0.0"
rollup-plugin-terser@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==
dependencies:
"@babel/code-frame" "^7.10.4"
jest-worker "^26.2.1"
serialize-javascript "^4.0.0"
terser "^5.0.0"
rollup@^2.62.0:
version "2.62.0"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.62.0.tgz#9e640b419fc5b9e0241844f6d55258bd79986ecc"
@ -4479,6 +4525,11 @@ rxjs@^7.4.0:
dependencies:
tslib "~2.1.0"
safe-buffer@^5.1.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
@ -4521,6 +4572,13 @@ semver@^7.2.1, semver@^7.3.2, semver@^7.3.5:
dependencies:
lru-cache "^6.0.0"
serialize-javascript@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
dependencies:
randombytes "^2.1.0"
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@ -4600,7 +4658,7 @@ slice-ansi@^5.0.0:
ansi-styles "^6.0.0"
is-fullwidth-code-point "^4.0.0"
source-map-support@^0.5.6:
source-map-support@^0.5.6, source-map-support@~0.5.20:
version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
@ -4618,11 +4676,16 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@^0.7.3:
source-map@^0.7.3, source-map@~0.7.2:
version "0.7.3"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
sourcemap-codec@^1.4.4:
version "1.4.8"
resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
spawn-command@^0.0.2-1:
version "0.0.2-1"
resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0"
@ -4782,6 +4845,15 @@ terminal-link@^2.0.0:
ansi-escapes "^4.2.1"
supports-hyperlinks "^2.0.0"
terser@^5.0.0:
version "5.10.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc"
integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==
dependencies:
commander "^2.20.0"
source-map "~0.7.2"
source-map-support "~0.5.20"
test-exclude@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"