1import { resolve, basename } from 'path';
2import commonjs from '@rollup/plugin-commonjs';
3import nodeResolve from '@rollup/plugin-node-resolve';
4import typescript from 'rollup-plugin-typescript2';
5import buble from '@rollup/plugin-buble';
6import babel from 'rollup-plugin-babel';
7import { terser } from 'rollup-plugin-terser';
8import compiler from '@ampproject/rollup-plugin-closure-compiler';
9
10const cwd = process.cwd();
11const pkgInfo = require('./package.json');
12const name = basename(pkgInfo.main, '.js');
13
14const terserPretty = terser({
15 sourcemap: true,
16 warnings: true,
17 ecma: 5,
18 keep_fnames: true,
19 ie8: false,
20 compress: {
21 pure_getters: true,
22 toplevel: true,
23 booleans_as_integers: false,
24 keep_fnames: true,
25 keep_fargs: true,
26 if_return: false,
27 ie8: false,
28 sequences: false,
29 loops: false,
30 conditionals: false,
31 join_vars: false
32 },
33 mangle: false,
34 output: {
35 beautify: true,
36 braces: true,
37 indent_level: 2
38 }
39});
40
41const terserMinified = terser({
42 sourcemap: true,
43 warnings: true,
44 ecma: 5,
45 ie8: false,
46 toplevel: true,
47 mangle: true,
48 compress: {
49 keep_infinity: true,
50 pure_getters: true,
51 passes: 10
52 },
53 output: {
54 comments: false
55 }
56});
57
58const importAllPlugin = ({ types: t }) => ({
59 visitor: {
60 VariableDeclarator(path) {
61 if (
62 t.isIdentifier(path.node.id) &&
63 t.isCallExpression(path.node.init) &&
64 t.isIdentifier(path.node.init.callee) &&
65 path.node.init.callee.name === 'require' &&
66 path.node.init.arguments.length === 1
67 ) {
68 path.parentPath.replaceWith(
69 t.importDeclaration(
70 [t.importNamespaceSpecifier(path.node.id)],
71 path.node.init.arguments[0]
72 )
73 );
74 }
75 }
76 }
77});
78
79const unwrapStatePlugin = ({ types: t }) => ({
80 pre() {
81 this.props = new Map();
82 this.test = node =>
83 /state$/i.test(node.id.name) ||
84 (node.init.properties.length === 1 && node.init.properties[0].key.name === 'contents');
85 },
86 visitor: {
87 VariableDeclarator(path) {
88 if (
89 t.isIdentifier(path.node.id) &&
90 t.isObjectExpression(path.node.init) &&
91 path.node.init.properties.every(
92 prop => t.isObjectProperty(prop) && t.isIdentifier(prop.key)
93 ) &&
94 this.test(path.node)
95 ) {
96 const id = path.node.id.name;
97 const properties = path.node.init.properties;
98 const propNames = new Set(properties.map(x => x.key.name));
99 const decl = properties.map(prop => {
100 const key = `${id}$${prop.key.name}`;
101 return t.variableDeclarator(t.identifier(key), prop.value);
102 });
103
104 this.props.set(id, propNames);
105 path.parentPath.replaceWithMultiple(t.variableDeclaration('let', decl));
106 }
107 },
108 MemberExpression(path) {
109 if (
110 t.isIdentifier(path.node.object) &&
111 this.props.has(path.node.object.name) &&
112 t.isIdentifier(path.node.property) &&
113 this.props.get(path.node.object.name).has(path.node.property.name)
114 ) {
115 const id = path.node.object.name;
116 const propName = path.node.property.name;
117 path.replaceWith(t.identifier(`${id}$${propName}`));
118 }
119 }
120 }
121});
122
123const makePlugins = isProduction =>
124 [
125 babel({
126 babelrc: false,
127 extensions: ['ts', 'tsx', 'js'],
128 exclude: 'node_modules/**',
129 presets: [],
130 plugins: ['@babel/plugin-syntax-typescript', importAllPlugin]
131 }),
132 typescript({
133 typescript: require('typescript'),
134 cacheRoot: './node_modules/.cache/.rts2_cache',
135 objectHashIgnoreUnknownHack: true,
136 useTsconfigDeclarationDir: true,
137 tsconfigOverride: {
138 compilerOptions: {
139 strict: false,
140 noUnusedParameters: false,
141 declaration: !isProduction,
142 declarationDir: resolve(cwd, './dist/types/'),
143 target: 'esnext',
144 module: 'es2015',
145 rootDir: cwd
146 }
147 }
148 }),
149 commonjs({
150 ignoreGlobal: true,
151 include: ['*', '**'],
152 extensions: ['.js', '.ts', '.tsx']
153 }),
154 nodeResolve({
155 mainFields: ['module', 'jsnext', 'main'],
156 extensions: ['.js', '.ts', '.tsx'],
157 browser: true
158 }),
159 buble({
160 transforms: {
161 unicodeRegExp: false,
162 dangerousForOf: true,
163 dangerousTaggedTemplateString: true
164 },
165 objectAssign: 'Object.assign',
166 exclude: 'node_modules/**'
167 }),
168 babel({
169 babelrc: false,
170 extensions: ['ts', 'tsx', 'js'],
171 exclude: 'node_modules/**',
172 presets: [],
173 plugins: ['babel-plugin-closure-elimination', unwrapStatePlugin]
174 }),
175 compiler({
176 compilation_level: 'SIMPLE_OPTIMIZATIONS'
177 }),
178 isProduction ? terserMinified : terserPretty
179 ].filter(Boolean);
180
181const config = {
182 input: './src/Wonka.ts',
183 onwarn: () => {},
184 external: () => false,
185 treeshake: {
186 propertyReadSideEffects: false
187 }
188};
189
190export default [
191 {
192 ...config,
193 plugins: makePlugins(false),
194 output: [
195 {
196 legacy: true,
197 freeze: false,
198 esModule: false,
199 file: `./dist/${name}.js`,
200 format: 'cjs'
201 },
202 {
203 legacy: true,
204 freeze: false,
205 esModule: false,
206 file: `./dist/${name}.mjs`,
207 format: 'esm'
208 }
209 ]
210 },
211 {
212 ...config,
213 plugins: makePlugins(true),
214 output: [
215 {
216 legacy: true,
217 freeze: false,
218 esModule: false,
219 file: `./dist/${name}.min.js`,
220 format: 'cjs'
221 }
222 ]
223 }
224];