diff --git a/.babelrc.js b/.babelrc.js index 0dc3e76f0..59b2c61e9 100644 --- a/.babelrc.js +++ b/.babelrc.js @@ -44,30 +44,35 @@ const plugins = [ ], ] +const importRedirect = [ + 'import-redirect', + { + redirect: { + '(adapters|decorators|utils|observation)(.+(?=\\/index\\.js)|.+(?=\\.js)|.+)': redirect( + '$1$2', + ), + Collection$: redirect('Collection'), + CollectionMap$: redirect('CollectionMap'), + Database$: redirect('Database'), + Model$: redirect('Model'), + Query$: redirect('Query'), + QueryDescription$: redirect('QueryDescription'), + RawRecord$: redirect('RawRecord'), + Relation$: redirect('Relation'), + Schema$: redirect('Schema'), + }, + suppressResolveWarning: true, + }, +] + module.exports = { env: { + development: { + plugins: [importRedirect, ...plugins], + }, production: { plugins: [ - [ - 'import-redirect', - { - redirect: { - '(adapters|decorators|utils|observation)(.+(?=\\/index\\.js)|.+(?=\\.js)|.+)': redirect( - '$1$2', - ), - Collection$: redirect('Collection'), - CollectionMap$: redirect('CollectionMap'), - Database$: redirect('Database'), - Model$: redirect('Model'), - Query$: redirect('Query'), - QueryDescription$: redirect('QueryDescription'), - RawRecord$: redirect('RawRecord'), - Relation$: redirect('Relation'), - Schema$: redirect('Schema'), - }, - suppressResolveWarning: true, - }, - ], + importRedirect, ...plugins, // console.log is expensive for performance on native // we don't want it on web either, but it's useful for development diff --git a/.eslintignore b/.eslintignore index 77ef295a7..ba2b5520f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ node_modules/ dist/ flow-typed/ +dev/ diff --git a/.flowconfig b/.flowconfig index 0255c24ba..aa54f5a73 100644 --- a/.flowconfig +++ b/.flowconfig @@ -2,6 +2,7 @@ /.cache /__tests__ /dist +/dev [include] diff --git a/.gitignore b/.gitignore index 0e5730f8c..b0e09f1c8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,6 @@ npm-debug.log yarn-error.log dist/ +dev/ *.tgz diff --git a/jest.config.js b/jest.config.js index 059c71bac..b98ce86f6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -28,5 +28,5 @@ module.exports = { restoreMocks: true, testMatch: ['**/__tests__/**/?(spec|test).js', '**/?(*.)(spec|test).js'], moduleFileExtensions: ['js'], - modulePathIgnorePatterns: ['/dist'], + modulePathIgnorePatterns: ['/dist', '/dev'], } diff --git a/package.json b/package.json index f1ee4c05e..6e56e8b32 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,9 @@ "description": "Build powerful React Native and React web apps that scale from hundreds to tens of thousands of records and remain fast", "version": "0.1.14", "scripts": { - "clean": "shx rm -rf ./dist", - "make": "NODE_ENV=production node ./scripts/make.js", + "build": "NODE_ENV=production node ./scripts/make.js", + "dev": "NODE_ENV=development node ./scripts/make.js", "release": "node ./scripts/publish.js", - "build": "npm-run-all clean make", "flow": "flow check", "eslint": "eslint ./src -c ./.eslintrc.yml --cache --cache-location ./.cache/.eslintcache", "test": "jest --config=./jest.config.js --forceExit --detectOpenHandles --no-cache" diff --git a/scripts/make.js b/scripts/make.js index 74eeae0fd..6cb1280e7 100644 --- a/scripts/make.js +++ b/scripts/make.js @@ -7,15 +7,14 @@ const { mapAsync, endsWith, both, - includes, prop, - all, replace, join, reduce, omit, merge, forEach, + tail, } = require('rambdax') const rollup = require('rollup') @@ -24,33 +23,38 @@ const mkdirp = require('mkdirp') const path = require('path') const fs = require('fs-extra') const prettyJson = require('json-stringify-pretty-compact') +const chokidar = require('chokidar') +const anymatch = require('anymatch') +const rimraf = require('rimraf') const pkg = require('../package.json') -const rollupConfig = require('./rollup.config') +const createRollupConfig = require('./rollup.config') const resolvePath = (...paths) => path.resolve(__dirname, '..', ...paths) +const isDevelopment = process.env.NODE_ENV === 'development' +const rollupConfig = createRollupConfig({ env: process.env.NODE_ENV }) const ESM_MODULES = 'esm' const CJS_MODULES = 'cjs' const SOURCE_PATH = resolvePath('src') const DIST_PATH = resolvePath('dist') +const DEV_PATH = resolvePath('dev') + +const DIR_PATH = isDevelopment ? DEV_PATH : DIST_PATH + const DO_NOT_BUILD_PATHS = [ - 'adapters/__tests__', - 'test.js', - 'type.js', - 'integrationTest.js', - '__mocks__', - 'Collection/RecordCache.js', + /adapters\/__tests__/, + /test\.js/, + /type\.js/, + /integrationTest\.js/, + /__mocks__/, + /Collection\/RecordCache\.js/, ] -const createModulePath = format => { - const modulePath = resolvePath(DIST_PATH, format) - return replace(SOURCE_PATH, modulePath) -} +const isNotIncludedInBuildPaths = value => !anymatch(DO_NOT_BUILD_PATHS, value) -const isNotIncludedInBuildPaths = value => - all(buildPath => !includes(buildPath, value), DO_NOT_BUILD_PATHS) +const cleanFolder = dir => rimraf.sync(dir) const takeFiles = pipe( prop('path'), @@ -63,7 +67,6 @@ const takeModules = pipe( ) const removeSourcePath = replace(SOURCE_PATH, '') - const toStringKeyValue = module => `'${module.key}': '${module.value}'` const indentLine = line => ` ${line},` const toStringObject = pipe( @@ -87,12 +90,20 @@ ${toStringObject(obj)} } ` +const createModulePath = format => { + const modulePath = resolvePath(DIR_PATH, format) + return replace(SOURCE_PATH, modulePath) +} + const createPathName = file => { const value = removeSourcePath(file) return endsWith('index.js', value) ? path.dirname(value) : replace('.js', '', value) } -const createModuleName = name => `${pkg.name}${name}` +const createModuleName = name => { + const module = tail(name) + return `${pkg.name}${module === '' ? module : `/${module}`}` +} const buildPathMapping = format => pipe( @@ -101,14 +112,14 @@ const buildPathMapping = format => return { key: createModuleName(name), - value: `${pkg.name}/${format}${name}`, + value: `${isDevelopment ? DEV_PATH : pkg.name}/${format}${name}`, } }), pathMappingTemplate, content => { try { - mkdirp.sync(resolvePath(DIST_PATH, format)) - fs.writeFileSync(resolvePath(DIST_PATH, format, 'path-mapping.js'), content) + mkdirp.sync(resolvePath(DIR_PATH, format)) + fs.writeFileSync(resolvePath(DIR_PATH, format, 'path-mapping.js'), content) } catch (err) { // eslint-disable-next-line console.error(err) @@ -158,25 +169,56 @@ const prepareJson = pipe( obj => prettyJson(obj), ) -const createDistFolder = () => mkdirp.sync(resolvePath(DIST_PATH)) +const createFolder = dir => mkdirp.sync(resolvePath(dir)) -const createPackageJson = obj => { +const createPackageJson = (dir, obj) => { const json = prepareJson(obj) - fs.writeFileSync(resolvePath(DIST_PATH, 'package.json'), json) + fs.writeFileSync(resolvePath(dir, 'package.json'), json) } -const copyFilesToDistFolder = forEach(file => - fs.copySync(resolvePath(file), resolvePath(DIST_PATH, file)), -) +const copyFiles = (dir, files) => + forEach(file => fs.copySync(resolvePath(file), resolvePath(dir, file)), files) + +if (isDevelopment) { + const buildCjsModule = buildModule(CJS_MODULES) + const buildEsmModule = buildModule(ESM_MODULES) -const buildModules = format => mapAsync(buildModule(format)) -const buildCjsModules = buildModules(CJS_MODULES) -const buildEsmModules = buildModules(ESM_MODULES) - -createDistFolder() -createPackageJson(pkg) -copyFilesToDistFolder(['LICENSE', 'README.md', 'yarn.lock', 'docs', 'src', 'native']) -buildCjsPathMapping(modules) -buildEsmPathMapping(modules) -buildEsmModules(modules) -buildCjsModules(modules) + const buildModules = file => { + buildCjsModule(file) + buildEsmModule(file) + } + + cleanFolder(DEV_PATH) + createFolder(DEV_PATH) + buildCjsPathMapping(modules) + buildEsmPathMapping(modules) + + chokidar + .watch(resolvePath('src'), { ignored: [...DO_NOT_BUILD_PATHS, /\.DS_Store/] }) + .on('all', (event, fileOrDir) => { + // eslint-disable-next-line + switch (event) { + case 'add': + case 'change': + // eslint-disable-next-line + console.log(`✓ ${removeSourcePath(fileOrDir)}`) + buildModules(fileOrDir) + break + default: + break + } + }) +} else { + const buildModules = format => mapAsync(buildModule(format)) + const buildCjsModules = buildModules(CJS_MODULES) + const buildEsmModules = buildModules(ESM_MODULES) + + cleanFolder(DIST_PATH) + createFolder(DIST_PATH) + createPackageJson(DIST_PATH, pkg) + copyFiles(DIST_PATH, ['LICENSE', 'README.md', 'yarn.lock', 'docs', 'src', 'native']) + buildCjsPathMapping(modules) + buildEsmPathMapping(modules) + buildEsmModules(modules) + buildCjsModules(modules) +} diff --git a/scripts/rollup.config.js b/scripts/rollup.config.js index 518f1d406..adb19a6b7 100644 --- a/scripts/rollup.config.js +++ b/scripts/rollup.config.js @@ -6,37 +6,40 @@ const { terser } = require('rollup-plugin-terser') const { rollupRx, rxExternalPaths } = require('./rollup.rx') -const env = process.env.NODE_ENV || 'development' +module.exports = options => { + const { env } = options + const isDevelopment = env === 'development' -module.exports = { - external: [ - 'lokijs', - 'lokijs/src/loki-indexed-adapter', - 'react-native', - 'async', - 'rxjs', - 'rxjs/operators', - 'rambdax', - 'sql-escape-string', - ...rxExternalPaths, - ], - experimentalCodeSplitting: true, - treeshake: true, - plugins: [ - rollupRx(), - resolve({ - customResolveOptions: { - moduleDirectory: ['node_modules'], - }, - }), - babel({ - runtimeHelpers: true, - exclude: 'node_modules/**', - }), - commonjs(), - replace({ - 'process.env.NODE_ENV': JSON.stringify(env), - }), - terser(), - ], + return { + external: [ + 'lokijs', + 'lokijs/src/loki-indexed-adapter', + 'react-native', + 'async', + 'rxjs', + 'rxjs/operators', + 'rambdax', + 'sql-escape-string', + ...rxExternalPaths, + ], + experimentalCodeSplitting: true, + treeshake: true, + plugins: [ + rollupRx(), + resolve({ + customResolveOptions: { + moduleDirectory: ['node_modules'], + }, + }), + babel({ + runtimeHelpers: true, + exclude: 'node_modules/**', + }), + commonjs(), + replace({ + 'process.env.NODE_ENV': JSON.stringify(env), + }), + ...(isDevelopment ? [] : [terser()]), + ], + } }