UNPKG

6.13 kBJavaScriptView Raw
1'use strict';
2
3/* eslint-disable no-console */
4
5const fs = require('fs');
6const path = require('path');
7const findup = require('findup');
8const semverUtils = require('semver-utils');
9const prettyjson = require('prettyjson');
10const merge = require('lodash/merge');
11const isFinite = require('lodash/isFinite');
12const isUndefined = require('lodash/isUndefined');
13const utils = require('./utils/utils');
14const consts = require('./consts');
15const DvhbWebpackError = require('./utils/error');
16
17const CONFIG_FILENAME = 'dvhb.config.js';
18const DEFAULT_CONFIG = {
19 title: 'Dvhb Webpack Starter kit',
20 sourceDir: 'src',
21 assetsDir: null,
22 distDir: 'dist',
23 viewsDir: 'src/views',
24 template: 'src/index.html',
25 serverHost: 'localhost',
26 serverPort: 3000,
27 verbose: false,
28 extendWebpackConfig: null
29};
30const DEPENDENCIES = [
31 {
32 package: 'babel-core',
33 name: 'Babel',
34 from: 6,
35 to: 6,
36 },
37 {
38 package: 'webpack',
39 name: 'Webpack',
40 from: 1,
41 to: 2,
42 },
43];
44
45/**
46 * Read, parse and validate config file or passed config.
47 *
48 * @param {object} [options] CLI options (e.g. {verbose: true} or {config: 'filename'}) or all config options.
49 * @returns {object}
50 */
51function getConfig(options) {
52 options = options || {};
53
54 let configFilepath;
55 let config;
56
57 // Read config options from a file
58 configFilepath = findConfig(options.config);
59 config = require(configFilepath);
60
61 validateConfig(config);
62
63 const configDir = configFilepath ? path.dirname(configFilepath) : process.cwd();
64
65 validateDependencies(configDir);
66
67 let assetsDir = null;
68 if (typeof config.assetsDir === 'string') {
69 assetsDir = path.resolve(configDir, config.assetsDir);
70 if (!utils.isDirectoryExists(assetsDir)) {
71 throw new DvhbWebpackError('DvhbWebpack: "assetsDir" directory not found: ' + assetsDir);
72 }
73 }
74 if (Array.isArray(config.assetsDir)) {
75 assetsDir = [];
76 config.assetsDir.forEach(function (dir) {
77 assetsDir.push(path.resolve(configDir, dir));
78 });
79 }
80
81 config = merge({}, DEFAULT_CONFIG, config);
82 config = merge({}, config, {
83 env: options.env || 'development',
84 verbose: !!options.verbose,
85 sourceDir: path.resolve(configDir, config.sourceDir),
86 distDir: path.resolve(configDir, config.distDir),
87 viewsDir: path.resolve(configDir, config.viewsDir),
88 assetsDir: assetsDir,
89 configDir,
90 });
91
92 if (config.template) {
93 config.template = path.resolve(configDir, config.template)
94 }
95
96 if (config.verbose) {
97 console.log();
98 console.log('Using config file:', configFilepath);
99 console.log(prettyjson.render(config));
100 console.log();
101 }
102
103 return config;
104}
105
106/**
107 * Find config file: use file specified in the command line or try to find up the file tree.
108 *
109 * @param {Object} [file] File name.
110 * @return {string} Config absolute file path.
111 */
112function findConfig(file) {
113 if (file) {
114 // Custom config location
115
116 const configFilepath = file[0] === '/' ? file : path.join(process.cwd(), file);
117 if (!fs.existsSync(configFilepath)) {
118 throw new DvhbWebpackError('DvhbWebpack config not found: ' + configFilepath + '.');
119 }
120
121 return configFilepath;
122 }
123
124 // Search config file in all parent directories
125
126 let configDir;
127 try {
128 configDir = findup.sync(__dirname, CONFIG_FILENAME);
129 }
130 catch (exception) {
131 throw new DvhbWebpackError('DvhbWebpack config not found: ' + CONFIG_FILENAME + '.');
132 }
133
134 return path.join(configDir, CONFIG_FILENAME);
135}
136
137/**
138 * Validate config.
139 *
140 * @param {Object} config Config options.
141 */
142function validateConfig(config) {
143 if (config.extendWebpackConfig && typeof config.extendWebpackConfig !== 'function') {
144 throw new DvhbWebpackError('DvhbWebpack: "extendWebpackConfig" option must be a function.');
145 }
146}
147
148/**
149 * Validate project’s Babel and Webpack versions.
150 *
151 * @param {string} configDir Config file directory.
152 */
153function validateDependencies(configDir) {
154 const packageJsonPath = path.join(findup.sync(configDir, 'package.json'), 'package.json');
155 const packageJson = require(packageJsonPath);
156 DEPENDENCIES.forEach(validateDependency.bind(null, packageJson));
157}
158
159/**
160 * Check versions of a project dependency.
161 *
162 * @param {Object} packageJson package.json.
163 * @param {Object} dependency Dependency details.
164 */
165function validateDependency(packageJson, dependency) {
166 const version = findDependency(dependency.package, packageJson);
167 if (!version) {
168 return;
169 }
170
171 let major;
172 try {
173 major = semverUtils.parseRange(version)[0].major;
174 }
175 catch (exception) {
176 console.log('DvhbWebpack: cannot parse ' + dependency.name + ' version which is "' + version + '".');
177 console.log('DvhbWebpack might not work properly. Please report this issue at ' + consts.BUGS_URL);
178 console.log();
179 }
180
181 if (major < dependency.from) {
182 throw new DvhbWebpackError('DvhbWebpack: ' + dependency.name + ' ' + dependency.from + ' is required, ' +
183 'you are using version ' + major + '.');
184 }
185 else if (major > dependency.to) {
186 console.log('DvhbWebpack: ' + dependency.name + ' is supported up to version ' + dependency.to + ', ' +
187 'you are using version ' + major + '.');
188 console.log('DvhbWebpack might not work properly, report bugs at ' + consts.BUGS_URL);
189 console.log();
190 }
191}
192
193/**
194 * Find package in project’s dependencies or devDependencies.
195 *
196 * @param {string} name Package name.
197 * @param {Object} packageJson package.json.
198 * @returns {string}
199 */
200function findDependency(name, packageJson) {
201 if (packageJson.dependencies && packageJson.dependencies[name]) {
202 return packageJson.dependencies[name];
203 }
204 if (packageJson.devDependencies && packageJson.devDependencies[name]) {
205 return packageJson.devDependencies[name];
206 }
207 return null;
208}
209
210module.exports = getConfig;