Skip to content

Commit 9bea617

Browse files
author
Harrison Ifeanyichukwu
committed
build: refactor rollup js build process
1 parent c2ce9db commit 9bea617

File tree

2 files changed

+184
-92
lines changed

2 files changed

+184
-92
lines changed

build.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
"uglify": true
77
},
88
"libConfig": {
9-
9+
"uglify": false
1010
}
1111
}

rollup.config.js

Lines changed: 183 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -5,153 +5,245 @@ import resolve from 'rollup-plugin-node-resolve';
55
import babel from 'rollup-plugin-babel';
66
import {uglify} from 'rollup-plugin-uglify';
77

8+
/**
9+
*@description - converts the letters into camel like cases
10+
*@param {string} value - the string word to convert
11+
*@param {string|RegExp} [delimiter=/[-_]/] - a delimiter string or regex pattern used in
12+
* finding split segments
13+
*@returns {string}
14+
*/
15+
function camelCase(value, delimiter = /[-_]/) {
16+
value = value.toString();
17+
let tokens = value.split(delimiter).map((token, idx) => {
18+
return idx === 0? token : token[0].toUpperCase() + token.substring(1);
19+
});
20+
return tokens.join('');
21+
}
22+
23+
/**
24+
* resolves the pattern into a regex object
25+
*@param {Array|string} patterns -array of patterns or string pattern
26+
*/
27+
function resolveRegex(patterns) {
28+
if (patterns === '*')
29+
return [new RegExp('.*')];
30+
31+
if (Object.prototype.toString.call(patterns) === '[object Array]') {
32+
return patterns.map((pattern) => {
33+
pattern = pattern.replace(/\./g, '\\.').replace(/\*{2}/g, '.*').replace(/\*/g, '[^/]+');
34+
return new RegExp(pattern, 'i');
35+
});
36+
}
37+
38+
return [];
39+
}
40+
841
/**
942
* returns the config for the given file
1043
*@param {boolean} _uglify - boolean value indicating if file should be minified
11-
*@param {string} format - the expected output format
12-
*@param {string} src - the file source directory
13-
*@param {string} dest - the file destination directory, omit the .js extension
44+
*@param {Object} options - object options
45+
*@param {string} options.format - the expected output format
46+
*@param {string} options.src - the file source directory
47+
*@param {string} options.dest - the file destination directory, omit the .js extension
1448
*@param {string} name - the file module name
1549
*@param {Array} externals - array of module externals
1650
*@returns {Object}
1751
*/
18-
function getConfig(_uglify, format, src, dest, name, externals) {
52+
function getConfig(_uglify, options, name, externals) {
1953
let plugins = [
2054
resolve(),
2155
babel({
2256
exclude: 'node_modules/**',
23-
plugins: ["external-helpers"]
57+
plugins: ['external-helpers']
2458
})
2559
];
2660

2761
if (_uglify)
2862
plugins.push(uglify());
2963

3064
return {
31-
input: src,
65+
input: options.src,
3266
output: {
33-
file: dest + (_uglify? '.min.js' : '.js'),
34-
format: format,
35-
name: name,
67+
file: options.dest + (_uglify? '.min' : '') + options.ext,
68+
format: options.format,
69+
name: camelCase(name),
3670
interop: false,
3771
//sourcemap: true
3872
},
3973
plugins: plugins,
40-
external: externals || []
74+
external: externals
4175
};
4276
}
4377

4478
/**
45-
* resolves the pattern into a regex object
46-
*@param {Array|string} patterns -array of patterns or string pattern
79+
* returns the allowed exports for each build kind
80+
*@param {Object} options - options object
81+
*@param {string} options.outDir - the out directory for the build kind
82+
*@param {string} options.format - the output format for all included modules in this build
83+
*@param {boolean} options.uglify - boolean value indicating if modules should be uglified
84+
*@param {boolean} options.uglifyOnly - boolean value indicating if only uglified outputs should
85+
* be produced
86+
*@param {Array} modules - the modules list to build from
87+
*@param {Array} externalModules - array of external modules
4788
*/
48-
function resolveRegex(patterns) {
49-
if (patterns === '*')
50-
return [new RegExp('.*')];
89+
function getExports(exports, options, modules, externalModules, includes, excludes) {
90+
let src = null,
91+
regexMatches = function(regex) {
92+
return regex.test(src);
93+
},
94+
filterExternalModules = function(externalModule) {
95+
return externalModule !== src;
96+
};
5197

52-
if (Object.prototype.toString.call(patterns) === '[object Array]') {
53-
return patterns.map((pattern) => {
54-
pattern = pattern.replace(/\./g, '\.').replace(/\*{2}/g, '.*').replace(/\*/g, '[^/]+');
55-
return new RegExp(pattern, 'i');
56-
});
57-
}
98+
for (let _module of modules) {
99+
src = _module.absPath + _module.ext;
100+
if (!includes.some(regexMatches) || excludes.some(regexMatches))
101+
continue;
102+
103+
let dest = options.outDir + '/' + _module.relPath;
104+
if (_module.isAsset) {
105+
if (options.copyAssets) {
106+
const dir = path.dirname(dest);
107+
if (!fs.existsSync(dir))
108+
fs.mkdirSync(dir);
109+
110+
fs.writeFileSync(dest, fs.readFileSync(src));
111+
}
112+
continue;
113+
}
58114

59-
return [];
115+
let externals = externalModules.filter(filterExternalModules);
116+
if(!options.uglifyOnly)
117+
exports.push(getConfig(false, {
118+
src: src,
119+
dest: dest,
120+
format:options.format,
121+
ext: _module.ext
122+
}, _module.name, externals));
123+
124+
if (options.uglifyOnly || options.uglify)
125+
exports.push(getConfig(true, {
126+
src: src,
127+
dest: dest,
128+
format:options.format,
129+
ext: _module.ext
130+
}, _module.name, externals));
131+
}
60132
}
61133

62134
/**
63135
* gets all modules
136+
*@param {Array} modules - array to store modules
64137
*@param {string} dir - the root module directory to iterate
65138
*@param {string} mainModuleName - the global module name for the main export file.
66139
* others are mapped to file names
67140
*@returns {Array}
68141
*/
69-
function getModules(dir, mainModuleName) {
70-
let modules = [];
71-
fs.readdirSync(path.resolve(__dirname, dir)).forEach(file => {
72-
let filePath = path.resolve(__dirname, dir) + '/' + file;
73-
if (fs.statSync(filePath).isFile()) {
74-
let name = path.basename(filePath, '.js');
75-
if(name === 'main')
76-
name = mainModuleName;
77-
78-
modules.push({name: name, path: filePath});
79-
}
80-
else {
81-
modules.push(...getModules(filePath));
142+
function getModules(modules, resolvedPath, mainModuleName, srcPaths, fileExtensions) {
143+
let files = fs.readdirSync(resolvedPath);
144+
for (let file of files) {
145+
let filePath = resolvedPath + '/' + file;
146+
if (!fs.statSync(filePath).isFile()) {
147+
getModules(modules, filePath, mainModuleName, [...srcPaths, file], fileExtensions);
148+
continue;
82149
}
83-
});
84-
return modules;
85-
}
86150

87-
/**
88-
* returns the allowed exports for each build kind
89-
*@param {string} outDir - the out directory for the build kind
90-
*@param {string} format - the output format for all included modules in this build kind
91-
*@param {Array} modules - the modules list to build from
92-
*@param {Array} externalModules - array of external modules
93-
*@returns {Array}
94-
*/
95-
function getExports(outDir, format, uglify, modules, externalModules, includes, excludes) {
96-
let exports = [],
97-
src = null,
98-
regexMatches = function(regex) {
99-
return regex.test(src);
100-
},
101-
filterExternalModules = function(externalModule) {
102-
return externalModule !== src;
103-
};
104-
105-
for (let _module of modules) {
106-
src = _module.path;
107-
if (includes.some(regexMatches) && !excludes.some(regexMatches)) {
108-
let dest = outDir + '/' + src.replace(/^.*\/src\//, '').replace(/\.js$/, ''),
109-
externals = externalModules.filter(filterExternalModules);
110-
111-
exports.push(getConfig(false, format, src, dest, _module.name, externals));
112-
if (uglify)
113-
exports.push(getConfig(true, format, src, dest, _module.name, externals));
151+
let baseName = '', extname = path.extname(file);
152+
for (const fileExtension of fileExtensions) {
153+
if (fileExtension === extname) {
154+
baseName = path.basename(file, fileExtension);
155+
break;
156+
}
114157
}
115-
}
116158

117-
return exports;
159+
modules.push({
160+
name: baseName === 'main'? mainModuleName : baseName,
161+
ext: baseName? extname : '',
162+
relPath: [...srcPaths, baseName || file].join('/'),
163+
absPath: resolvedPath + '/' + (baseName || file),
164+
isAsset: baseName? false : true
165+
});
166+
}
167+
return modules;
118168
}
119169

170+
//import build configurations
120171
import buildConfig from './build.config.json';
121172

122-
let config = buildConfig;
173+
//copy config
174+
let config = buildConfig,
175+
distConfig = typeof config.distConfig !== 'undefined'? config.distConfig : {},
176+
libConfig = typeof config.libConfig !== 'undefined'? config.libConfig : {};
123177

124-
if(typeof config.distConfig === 'undefined')
125-
config.distConfig = {};
178+
//resolve uglifyOnly settings and src directory settings
179+
config.uglifyOnly = typeof config.uglifyOnly !== 'undefined'? config.uglifyOnly : false;
180+
config.srcDir = typeof config.srcDir !== 'undefined'? config.srcDir : 'src';
181+
config.copyAssets = typeof config.copyAssets !== 'undefined'? config.copyAssets : false;
126182

127-
if (typeof config.libConfig === 'undefined')
128-
config.libConfig = {};
183+
//resolve and extend external modules
184+
let externalModules = [];
185+
if (config.externalModules)
186+
externalModules.push(...config.externalModules);
129187

130-
//get modules & external modules
131-
let modules = getModules('src', config.mainModuleName || 'Module'),
132-
externalModules = modules.map(module => module.path);
188+
//resolve and extend file extensions
189+
let fileExtensions = ['.js'];
190+
if(config.fileExtensions)
191+
fileExtensions.push(...config.fileExtensions);
133192

134193
//resolve the default includes and exclude patterns
135194
let includes = resolveRegex(config.include || '*'),
136195
excludes = resolveRegex(config.exclude || null);
137196

138-
export default [
139-
...getExports(
140-
'lib',
141-
config.libConfig.format || 'cjs',
142-
config.libConfig.uglify? true : config.uglify,
197+
//get modules & extend external modules
198+
let modules = getModules(
199+
[],
200+
path.resolve(__dirname, config.srcDir),
201+
config.mainModuleName || 'Module',
202+
[],
203+
fileExtensions
204+
);
205+
206+
externalModules = [
207+
...externalModules,
208+
...modules.reduce((result, current) => {
209+
result.push(current.absPath + current.ext);
210+
return result;
211+
}, [])
212+
];
213+
214+
let exports = [];
215+
216+
//if lib config build is not disabled
217+
if (!libConfig.disabled)
218+
getExports(
219+
exports,
220+
{
221+
outDir: path.resolve(__dirname, libConfig.outDir || 'lib'),
222+
format: libConfig.format || 'cjs',
223+
uglifyOnly: typeof libConfig.uglifyOnly !== 'undefined'? libConfig.uglifyOnly : config.uglifyOnly,
224+
uglify: libConfig.uglify? true : config.uglify,
225+
copyAssets: typeof libConfig.copyAssets !== 'undefined'? libConfig.copyAssets : config.copyAssets
226+
},
143227
modules,
144228
externalModules,
145-
config.libConfig.include? resolveRegex(config.libConfig.include) : includes,
146-
config.libConfig.exclude? resolveRegex(config.libConfig.exclude) : excludes
147-
),
148-
...getExports(
149-
'dist',
150-
config.distConfig.format || 'iife',
151-
config.distConfig.uglify? true : config.uglify,
229+
libConfig.include? resolveRegex(libConfig.include) : includes,
230+
libConfig.exclude? resolveRegex(libConfig.exclude) : excludes
231+
);
232+
233+
if (!distConfig.disabled)
234+
getExports(
235+
exports,
236+
{
237+
outDir: path.resolve(__dirname, distConfig.outDir || 'dist'),
238+
format: distConfig.format || 'iife',
239+
uglifyOnly: typeof distConfig.uglifyOnly !== 'undefined'? distConfig.uglifyOnly : config.uglifyOnly,
240+
uglify: distConfig.uglify? true : config.uglify,
241+
copyAssets: typeof distConfig.copyAssets !== 'undefined'? distConfig.copyAssets : config.copyAssets
242+
},
152243
modules,
153244
[],
154-
config.distConfig.include? resolveRegex(config.distConfig.include) : includes,
155-
config.distConfig.exclude? resolveRegex(config.distConfig.exclude) : excludes
156-
)
157-
];
245+
distConfig.include? resolveRegex(distConfig.include) : includes,
246+
distConfig.exclude? resolveRegex(distConfig.exclude) : excludes
247+
);
248+
249+
export default exports;

0 commit comments

Comments
 (0)