-
Notifications
You must be signed in to change notification settings - Fork 356
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
325 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
'use strict'; | ||
|
||
const esDefaultOpts = require('esformatter/lib/preset/default.json'); | ||
|
||
const esOpts = Object.assign({}, esDefaultOpts, { | ||
'lineBreak': { | ||
'before': { | ||
'AssignmentExpression': '>=2', | ||
'ClassDeclaration': 2, | ||
'EndOfFile': 1 | ||
}, | ||
'after': { | ||
'ClassClosingBrace': 2, | ||
'FunctionDeclaration': '>=2', | ||
'BlockStatementClosingBrace': '>=2' | ||
} | ||
} | ||
}); | ||
|
||
module.exports = { | ||
esOpts | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
'use strict'; | ||
|
||
const Generators = require('yeoman-generator'); | ||
const classify = require('underscore.string').classify; | ||
const underscored = require('underscore.string').underscored; | ||
|
||
const formatCode = require('./utils').formatCode; | ||
const getModifiedConfigModuleIndex = require('./utils').getModifiedConfigModuleIndex; | ||
|
||
|
||
class EnvGenerator extends Generators.Base { | ||
|
||
constructor(args, options) { | ||
super(args, options); | ||
|
||
this.argument('envName', { type: String, required: true }); | ||
} | ||
|
||
configuring() { | ||
|
||
/** | ||
* Currently used major version of the generator (defaults to latest stable). | ||
* @type {number} | ||
*/ | ||
this.generatorVersion = this.config.get('generatedWithVersion') || 3; | ||
|
||
// Make sure we don't try to use this subgen on V3 or lower. | ||
if (this.generatorVersion < 4) { | ||
this.env.error('Setting up new envs is only supported in generator versions 4+'); | ||
} | ||
} | ||
|
||
writing() { | ||
const classedEnv = classify(this.envName); | ||
const snakedEnv = underscored(this.envName.toLowerCase()); | ||
|
||
// Write conf/webpack/<EnvName>.js | ||
this.fs.copyTpl( | ||
this.templatePath(`${this.generatorVersion}/Env.js`), | ||
this.destinationPath(`conf/webpack/${classedEnv}.js`), | ||
{ envName: snakedEnv } | ||
); | ||
|
||
// Write src/config/<env_name>.js | ||
this.fs.copyTpl( | ||
this.templatePath(`${this.generatorVersion}/runtimeConfig.js`), | ||
this.destinationPath(`src/config/${snakedEnv}.js`), | ||
{ envName: snakedEnv } | ||
); | ||
|
||
// Write conf/webpack/index.js | ||
const moduleIndexPath = this.destinationPath('conf/webpack/index.js'); | ||
const updatedModuleIndex = formatCode( | ||
getModifiedConfigModuleIndex(this.fs.read(moduleIndexPath), snakedEnv, classedEnv) | ||
); | ||
this.fs.write(this.destinationPath('conf/webpack/index.js'), formatCode(updatedModuleIndex)); | ||
} | ||
|
||
} | ||
|
||
module.exports = EnvGenerator; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
'use strict'; | ||
|
||
/** | ||
* Default dev server configuration. | ||
*/ | ||
const webpack = require('webpack'); | ||
const WebpackBaseConfig = require('./Base'); | ||
|
||
class WebpackDevConfig extends WebpackBaseConfig { | ||
|
||
constructor() { | ||
super(); | ||
this.config = { | ||
// Update your env-specific configuration here! | ||
// To start, look at ./Dev.js or ./Dist.js for two example configurations | ||
// targeted at production or development builds. | ||
}; | ||
} | ||
|
||
/** | ||
* Get the environment name | ||
* @return {String} The current environment | ||
*/ | ||
get env() { | ||
return '<%= envName %>'; | ||
} | ||
} | ||
|
||
module.exports = WebpackDevConfig; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import baseConfig from './base'; | ||
|
||
const config = { | ||
appEnv: '<%= envName %>', | ||
}; | ||
|
||
export default Object.freeze(Object.assign({}, baseConfig, config)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
'use strict'; | ||
|
||
const acorn = require('acorn'); | ||
const escodegen = require('escodegen'); | ||
const esformatter = require('esformatter'); | ||
const jp = require('jsonpath'); | ||
|
||
const esOpts = require('./constants').esOpts; | ||
|
||
|
||
/** | ||
* Returns an AST Node for a {@code Property} in the {@code module.exports} object. | ||
* | ||
* @param {string} envName | ||
* @return {Object} | ||
*/ | ||
function createExportNode(envName) { | ||
return { | ||
'type': 'Property', | ||
'method': false, | ||
'shorthand': true, | ||
'computed': false, | ||
'key': { | ||
'type': 'Identifier', | ||
'name': envName | ||
}, | ||
'kind': 'init', | ||
'value': { | ||
'type': 'Identifier', | ||
'name': envName | ||
} | ||
} | ||
} | ||
|
||
|
||
/** | ||
* Returns updated index module requiring and exporting the newly created environment. | ||
* | ||
* @param {string} fileStr | ||
* @param {string} snakedEnv | ||
* @param {string} classedEnv | ||
* @return {string} file contents of updated conf/webpack/index.js | ||
*/ | ||
function getModifiedConfigModuleIndex(fileStr, snakedEnv, classedEnv) { | ||
// TODO [sthzg] we might want to rewrite the AST-mods in this function using a walker. | ||
|
||
const moduleFileAst = acorn.parse(fileStr, { module: true }); | ||
|
||
// if required env was already created, just return the original string | ||
if (jp.paths(moduleFileAst, `$..[?(@.value=="./${classedEnv}" && @.type=="Literal")]`).length > 0) { | ||
return fileStr; | ||
} | ||
|
||
// insert require call for the new env | ||
const envImportAst = acorn.parse(`const ${snakedEnv} = require('./${classedEnv}');`); | ||
const insertAt = jp.paths(moduleFileAst, '$..[?(@.name=="require")]').pop()[2] + 1; | ||
moduleFileAst.body.splice(insertAt, 0, envImportAst); | ||
|
||
// add new env to module.exports | ||
const exportsAt = jp.paths(moduleFileAst, '$..[?(@.name=="exports")]').pop()[2]; | ||
moduleFileAst.body[exportsAt].expression.right.properties.push(createExportNode(snakedEnv)); | ||
|
||
return escodegen.generate(moduleFileAst, { format: { indent: { style: ' ' } } }); | ||
} | ||
|
||
|
||
/** | ||
* Returns a beautified representation of {@code fileStr}. | ||
* | ||
* @param {string} fileStr | ||
* @return {string} | ||
*/ | ||
function formatCode(fileStr) { | ||
return esformatter.format(fileStr, esOpts); | ||
} | ||
|
||
|
||
module.exports = { | ||
createExportNode, | ||
formatCode, | ||
getModifiedConfigModuleIndex | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
const foo = require('path'); | ||
|
||
module.exports = { | ||
foo | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
'use strict'; | ||
|
||
const acorn = require('acorn'); | ||
const assert = require('yeoman-assert'); | ||
const fs = require('fs-extra'); | ||
const helpers = require('yeoman-test'); | ||
const path = require('path'); | ||
const walk = require('acorn/dist/walk'); | ||
|
||
|
||
/** | ||
* Returns absolute path to (sub-)generator with {@code name}. | ||
* @param {string} name | ||
*/ | ||
const genpath = (name) => | ||
path.join(__dirname, '../../../generators', name); | ||
|
||
/** | ||
* A mocked generator config object. | ||
* @type {{appName: string, style: string, cssmodules: boolean, postcss: boolean, generatedWithVersion: number}} | ||
*/ | ||
const cfg = { | ||
appName: 'testCfg', | ||
style: 'css', | ||
cssmodules: false, | ||
postcss: false, | ||
generatedWithVersion: 4 | ||
}; | ||
|
||
|
||
describe('react-webpack:setup-env', function () { | ||
|
||
describe('react-webpack:setup-env foobar', function () { | ||
before(function () { | ||
return helpers | ||
.run(genpath('setup-env')) | ||
.withArguments(['foobar']) | ||
.withLocalConfig(cfg) | ||
.inTmpDir(function (dir) { | ||
fs.copySync( | ||
path.join(__dirname, 'assets/moduleIndex.js'), | ||
path.join(dir, 'conf/webpack/index.js') | ||
); | ||
}) | ||
.toPromise(); | ||
}); | ||
|
||
it('creates env files', function () { | ||
assert.file(['conf/webpack/Foobar.js']); | ||
assert.file(['src/config/foobar.js']); | ||
}); | ||
|
||
it('requires the new env in conf/webpack/index.js', function () { | ||
assert.fileContent( | ||
'conf/webpack/index.js', | ||
/const foobar = require\('\.\/Foobar'\)/ | ||
); | ||
}); | ||
|
||
it('exports the new env from conf/webpack/index.js', function () { | ||
const fileStr = fs.readFileSync('conf/webpack/index.js').toString(); | ||
const ast = acorn.parse(fileStr); | ||
|
||
let found = false; | ||
walk.simple(ast, { | ||
'Property': (node) => { | ||
if (node.key.name === 'foobar' && node.value.name === 'foobar') { | ||
found = true; | ||
} | ||
} | ||
}); | ||
|
||
assert(found, 'Did not find a key and value of `foobar` on the module.exports AST node'); | ||
}); | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.