Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat: scaffolding aurelia plugin project
supersedes #793, closes #658
  • Loading branch information
3cp committed Mar 27, 2019
1 parent 71504b5 commit f5b2367
Show file tree
Hide file tree
Showing 42 changed files with 925 additions and 63 deletions.
9 changes: 7 additions & 2 deletions lib/commands/new/command.js
Expand Up @@ -187,8 +187,13 @@ ${cmd('--install-deps yarn')}, or ${cmd('--install-deps npm')}, or shorter form
message += `Then run your new app in dev mode with ${runCommand}.\n`; message += `Then run your new app in dev mode with ${runCommand}.\n`;
} }


message += `If you want to build your app for production, run ${cmd('au build --env prod')}.\n`; if (applicable(features, 'plugin')) {
message += `If you need help, simply run ${cmd('au help')}.\n`; message += `If you want to build the plugin, run ${cmd('au build-plugin')}.\n`;
message += 'Please read README.md file for more instructions.\n';
} else {
message += `If you want to build your app for production, run ${cmd('au build --env prod')}.\n`;
message += `If you need help, simply run ${cmd('au help')}.\n`;
}


await this.logTitle('Congratulations!'); await this.logTitle('Congratulations!');
await this.logBody(`Your Project "${projectName}" Has Been Created!`); await this.logBody(`Your Project "${projectName}" Has Been Created!`);
Expand Down
5 changes: 5 additions & 0 deletions lib/commands/new/command.json
Expand Up @@ -14,6 +14,11 @@
"description": "Creates a new project with the current working directory as the root of the project instead of creating a new project folder.", "description": "Creates a new project with the current working directory as the root of the project instead of creating a new project folder.",
"type": "boolean" "type": "boolean"
}, },
{
"name": "plugin",
"description": "Creates a new Aurelia plugin project.",
"type": "boolean"
},
{ {
"name": "unattended", "name": "unattended",
"description": "Creates project in unattended mode. It will fail if there is any conflicting file in target folder.", "description": "Creates project in unattended mode. It will fail if there is any conflicting file in target folder.",
Expand Down
10 changes: 7 additions & 3 deletions lib/workflow/applicable.js
Expand Up @@ -28,7 +28,11 @@ module.exports = function(features, condition) {
}) })
.join(' '); .join(' ');


// Eval expression like "! true || false" try {
// eslint-disable-next-line no-new-func // Eval expression like "! true || false"
return (new Function(`return ${expression};`))(); // eslint-disable-next-line no-new-func
return (new Function(`return ${expression};`))();
} catch (e) {
throw new Error(`Condition:${condition} error:${e.message}`);
}
}; };
23 changes: 17 additions & 6 deletions lib/workflow/questionnaire.js
Expand Up @@ -2,12 +2,20 @@
// We use value 'none' as a convention for no feature selected, // We use value 'none' as a convention for no feature selected,
// because enquirer doesn't support empty string '' as a value. // because enquirer doesn't support empty string '' as a value.


exports.pickPlugin = {
// add "plugin" to feature set for pluginFlow.
// because this only provides one choice (default choice), it
// is never prompted to end user.
choices: [{value: 'plugin'}]
};

exports.askBundler = { exports.askBundler = {
message: 'Which bundler would you like to use?', message: 'Which bundler would you like to use?',
choices: [{ choices: [{
value: 'webpack', value: 'webpack',
message: 'Webpack', message: 'Webpack',
hint: 'A powerful and popular bundler for JavaScript.' hint: 'A powerful and popular bundler for JavaScript.',
if: '!plugin'
}, { }, {
value: 'cli-bundler', value: 'cli-bundler',
message: "CLI's built-in bundler with an AMD module loader", message: "CLI's built-in bundler with an AMD module loader",
Expand All @@ -24,11 +32,13 @@ exports.askLoader = {
}, { }, {
value: 'alameda', value: 'alameda',
message: 'Alameda', message: 'Alameda',
hint: 'Alameda is a modern version of RequireJS using promises and native es6 features (modern browsers only).' hint: 'Alameda is a modern version of RequireJS using promises and native es6 features (modern browsers only).',
if: '!plugin'
}, { }, {
value: 'systemjs', value: 'systemjs',
message: 'SystemJS', message: 'SystemJS',
hint: 'SystemJS is Dynamic ES module loader, the most versatile module loader for JavaScript.' hint: 'SystemJS is Dynamic ES module loader, the most versatile module loader for JavaScript.',
if: '!plugin'
}], }],
// This if condition is not an enquirer feature. // This if condition is not an enquirer feature.
// This is our convention, check ./applicable.js for acceptable expressions // This is our convention, check ./applicable.js for acceptable expressions
Expand Down Expand Up @@ -60,7 +70,8 @@ exports.askPlatform = {
}, { }, {
value: 'dotnet-core', value: 'dotnet-core',
message: '.NET Core', message: '.NET Core',
hint: 'A powerful, patterns-based way to build dynamic websites with .NET Core.' hint: 'A powerful, patterns-based way to build dynamic websites with .NET Core.',
if: '!plugin'
}] }]
}; };


Expand Down Expand Up @@ -95,7 +106,7 @@ exports.askMarkupProcessor = {
}; };


exports.askCssProcessor = { exports.askCssProcessor = {
message: 'What css processor would you like to use?', message: 'What css preprocessor would you like to use?',
choices: [{ choices: [{
value: 'none', value: 'none',
message: 'None', message: 'None',
Expand Down Expand Up @@ -206,7 +217,7 @@ exports.askPluginScaffold = {
choices: [{ choices: [{
value: 'plugin-scaffold-minimum', value: 'plugin-scaffold-minimum',
message: 'None', message: 'None',
hint: 'Just a bare minimum Aurelia plugin.' hint: 'Just a bare minimum Aurelia plugin with one custom element.'
}, { }, {
value: 'plugin-scaffold-basic', value: 'plugin-scaffold-basic',
message: 'Basic', message: 'Basic',
Expand Down
74 changes: 37 additions & 37 deletions lib/workflow/select-features.js
@@ -1,6 +1,6 @@
const _ = require('lodash');
const runQuestionnaire = require('./run-questionnaire'); const runQuestionnaire = require('./run-questionnaire');
const { const {
pickPlugin,
askBundler, askBundler,
askLoader, askLoader,
askHttp, askHttp,
Expand Down Expand Up @@ -43,9 +43,6 @@ module.exports = async function(preselectedFeatures = [], opts = {}, _debug = []
if (flow === 'app') { if (flow === 'app') {
features = await appFlow(features, flowUnattended, _debug); features = await appFlow(features, flowUnattended, _debug);
} else if (flow === 'plugin') { } else if (flow === 'plugin') {
// Plugin skeleton is only based on cli-bundler.
// Don't allow user to overwrite cli-bundler with webpack
_.pull(features, 'webpack');
features = await pluginFlow(features, flowUnattended, _debug); features = await pluginFlow(features, flowUnattended, _debug);
} else { } else {
throw new Error(`Workflow "${flow}" is not recognizable.`); throw new Error(`Workflow "${flow}" is not recognizable.`);
Expand All @@ -62,9 +59,9 @@ const PRESETS = {
'default-esnext': {flow: 'app', recommendedFeatures: ['jest', 'vscode'], unattended: true}, 'default-esnext': {flow: 'app', recommendedFeatures: ['jest', 'vscode'], unattended: true},
'default-typescript': {flow: 'app', recommendedFeatures: ['jest', 'typescript', 'vscode'], unattended: true}, 'default-typescript': {flow: 'app', recommendedFeatures: ['jest', 'typescript', 'vscode'], unattended: true},
'custom-app': {flow: 'app'}, 'custom-app': {flow: 'app'},
'default-plugin-esnext': {flow: 'plugin', recommendedFeatures: ['cli-bundler', 'requirejs', 'jest', 'vscode'], unattended: true}, 'default-plugin-esnext': {flow: 'plugin', recommendedFeatures: ['jest', 'vscode'], unattended: true},
'default-plugin-typescript': {flow: 'plugin', recommendedFeatures: ['cli-bundler', 'requirejs', 'jest', 'typescript', 'vscode'], unattended: true}, 'default-plugin-typescript': {flow: 'plugin', recommendedFeatures: ['jest', 'typescript', 'vscode'], unattended: true},
'custom-plugin': {flow: 'plugin', recommendedFeatures: ['cli-bundler', 'requirejs']} 'custom-plugin': {flow: 'plugin'}
}; };


async function selectWorkFlow(opts, _debug) { async function selectWorkFlow(opts, _debug) {
Expand All @@ -76,36 +73,35 @@ async function selectWorkFlow(opts, _debug) {
} else { } else {
const ans = await runQuestionnaire([], [{ const ans = await runQuestionnaire([], [{
message: 'Would you like to use the default setup or customize your choices?', message: 'Would you like to use the default setup or customize your choices?',
choices: [{ choices: opts.plugin ?
value: 'default-esnext', // plugin flows
message: 'Default ESNext App', [{
hint: 'A basic app with Babel and Webpack.' value: 'default-plugin-esnext',
}, { message: 'Default ESNext Aurelia Plugin',
value: 'default-typescript', hint: 'A basic Aurelia plugin with Babel'
message: 'Default TypeScript App', }, {
hint: 'A basic app with TypeScript and Webpack.' value: 'default-plugin-typescript',
}, { message: 'Default TypeScript Aurelia Plugin',
value: 'custom-app', hint: 'A basic Aurelia plugin with TypeScript'
message: 'Custom App', }, {
hint: 'Select bundler, loader, transpiler, CSS pre-processor and more.' value: 'custom-plugin',
} message: 'Custom Aurelia Plugin',
/* TODO enable plugin flow after providing the plugin skeleton hint: 'Select transpiler, CSS pre-processor and more.'
{ }] :
role: 'separator' // app flows
}, { [{
value: 'default-plugin-esnext', value: 'default-esnext',
message: 'Default ESNext Aurelia Plugin', message: 'Default ESNext App',
hint: 'A basic Aurelia plugin with Babel' hint: 'A basic app with Babel and Webpack.'
}, { }, {
value: 'default-plugin-typescript', value: 'default-typescript',
message: 'Default TypeScript Aurelia Plugin', message: 'Default TypeScript App',
hint: 'A basic Aurelia plugin with TypeScript' hint: 'A basic app with TypeScript and Webpack.'
}, { }, {
value: 'custom-plugin', value: 'custom-app',
message: 'Custom Aurelia Plugin', message: 'Custom App',
hint: 'Select transpiler, CSS pre-processor and more.' hint: 'Select bundler, loader, transpiler, CSS pre-processor and more.'
} */ }]
]
}], false, _debug); }], false, _debug);


workflow = ans[0]; workflow = ans[0];
Expand Down Expand Up @@ -133,6 +129,10 @@ async function appFlow(features, unattended, _debug) {


async function pluginFlow(features, unattended, _debug) { async function pluginFlow(features, unattended, _debug) {
return await runQuestionnaire(features, [ return await runQuestionnaire(features, [
pickPlugin,
askBundler,
askLoader,
askPlatform,
askTranspiler, askTranspiler,
askMarkupProcessor, askMarkupProcessor,
askCssProcessor, askCssProcessor,
Expand Down
2 changes: 2 additions & 0 deletions skeleton/cli-bundler/README.md
Expand Up @@ -12,6 +12,8 @@ To change dev server port, do `au run --port 8888`.
To install new npm packages automatically, do `au run --auto-install` To install new npm packages automatically, do `au run --auto-install`
// @endif // @endif


// @if !feat.plugin
## Build for production ## Build for production


Run `au build --env prod`. Run `au build --env prod`.
// @endif
57 changes: 49 additions & 8 deletions skeleton/cli-bundler/aurelia_project/aurelia.json
Expand Up @@ -6,36 +6,77 @@
["@babel/plugin-transform-modules-amd", {"loose": true}] ["@babel/plugin-transform-modules-amd", {"loose": true}]
] ]
}, },
"source": "src/**/*.js",
"source": [
// @if feat.plugin
"dev-app/**/*.js",
// @endif
"src/**/*.js"
],
// @endif // @endif


// @if feat.typescript // @if feat.typescript
"dtsSource": ["./types/**/*.d.ts"], "dtsSource": ["./types/**/*.d.ts"],
"source": "src/**/*.ts", "source": [
// @if feat.plugin
"dev-app/**/*.ts",
// @endif
"src/**/*.ts"
],
// @endif // @endif
}, },
"markupProcessor": { "markupProcessor": {
"source": "src/**/*.html" "source": [
// @if feat.plugin
"dev-app/**/*.html",
// @endif
"src/**/*.html"
],
}, },
"cssProcessor": { "cssProcessor": {
// @if ! (feat.less || feat.sass || feat.stylus) // @if ! (feat.less || feat.sass || feat.stylus)
"source": "src/**/*.css" "source": [
// @if feat.plugin
"dev-app/**/*.css",
// @endif
"src/**/*.css"
],
// @endif // @endif


// @if feat.less // @if feat.less
"source": "src/**/*.less" "source": [
// @if feat.plugin
"dev-app/**/*.less",
// @endif
"src/**/*.less"
],
// @endif // @endif


// @if feat.sass // @if feat.sass
"source": "src/**/*.scss" "source": [
// @if feat.plugin
"dev-app/**/*.scss",
// @endif
"src/**/*.scss"
],
// @endif // @endif


// @if feat.stylus // @if feat.stylus
"source": "src/**/*.styl" "source": [
// @if feat.plugin
"dev-app/**/*.styl",
// @endif
"src/**/*.styl"
],
// @endif // @endif
}, },
"jsonProcessor": { "jsonProcessor": {
"source": "src/**/*.json" "source": [
// @if feat.plugin
"dev-app/**/*.json",
// @endif
"src/**/*.json"
],
}, },
// @if feat.karma // @if feat.karma
"unitTestRunner": { "unitTestRunner": {
Expand Down
33 changes: 33 additions & 0 deletions skeleton/cli-bundler/aurelia_project/tasks/process-css.ext
Expand Up @@ -78,3 +78,36 @@ export default function processCSS() {
// @endif // @endif
.pipe(build.bundle()); .pipe(build.bundle());
} }

// @if feat.plugin
export function pluginCSS(dest) {
return function processPluginCSS() {
return gulp.src(project.plugin.source.css)
// @if feat.less || feat.stylus
.pipe(plumber({ errorHandler: notify.onError('Error: <%= error.message %>') }))
// @endif
// @if feat.less
.pipe(less())
// @endif
// @if feat.sass
.pipe(sass().on('error', sass.logError))
// @endif
// @if feat.stylus
.pipe(stylus())
// @endif
// @if feat['postcss-basic']
.pipe(postcss([
autoprefixer({browsers: ['last 2 version']})
]))
// @endif
// @if feat['postcss-typical']
.pipe(postcss([
autoprefixer({browsers: ['last 2 version']}),
postcssUrl({url: 'inline', encodeType: 'base64'}),
cssnano()
]))
// @endif
.pipe(gulp.dest(dest));
};
}
// @endif
9 changes: 9 additions & 0 deletions skeleton/cli-bundler/aurelia_project/tasks/process-json.ext
Expand Up @@ -12,3 +12,12 @@ export default function processJson() {
return gulp.src(project.jsonProcessor.source, {since: gulp.lastRun(processJson)}) return gulp.src(project.jsonProcessor.source, {since: gulp.lastRun(processJson)})
.pipe(build.bundle()); .pipe(build.bundle());
} }

// @if feat.plugin
export function pluginJson(dest) {
return function processPluginJson() {
return gulp.src(project.plugin.source.json)
.pipe(gulp.dest(dest));
};
}
// @endif
25 changes: 25 additions & 0 deletions skeleton/cli-bundler/aurelia_project/tasks/process-markup.ext
Expand Up @@ -39,3 +39,28 @@ export default function processMarkup() {
// @endif // @endif
.pipe(build.bundle()); .pipe(build.bundle());
} }

// @if feat.plugin
export function pluginMarkup(dest) {
return function processPluginMarkup() {
return gulp.src(project.plugin.source.html)
// @if feat['htmlmin-min'] || feat['htmlmin-max']
.pipe(htmlmin({
// @if feat['htmlmin-max']
collapseInlineTagWhitespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
// @endif
removeComments: true,
collapseWhitespace: true,
minifyCSS: true,
minifyJS: true,
ignoreCustomFragments: [/\${.*?}/g] // ignore interpolation expressions
}))
// @endif
.pipe(gulp.dest(dest));
};
}
// @endif

0 comments on commit f5b2367

Please sign in to comment.