Skip to content

Commit

Permalink
feat: scaffolding aurelia plugin project
Browse files Browse the repository at this point in the history
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
Original file line number Diff line number Diff line change
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 += `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`;
if (applicable(features, 'plugin')) {
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.logBody(`Your Project "${projectName}" Has Been Created!`);
Expand Down
5 changes: 5 additions & 0 deletions lib/commands/new/command.json
Original file line number Diff line number Diff line change
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.",
"type": "boolean"
},
{
"name": "plugin",
"description": "Creates a new Aurelia plugin project.",
"type": "boolean"
},
{
"name": "unattended",
"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
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ module.exports = function(features, condition) {
})
.join(' ');

// Eval expression like "! true || false"
// eslint-disable-next-line no-new-func
return (new Function(`return ${expression};`))();
try {
// Eval expression like "! true || false"
// 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
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@
// We use value 'none' as a convention for no feature selected,
// 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 = {
message: 'Which bundler would you like to use?',
choices: [{
value: 'webpack',
message: 'Webpack',
hint: 'A powerful and popular bundler for JavaScript.'
hint: 'A powerful and popular bundler for JavaScript.',
if: '!plugin'
}, {
value: 'cli-bundler',
message: "CLI's built-in bundler with an AMD module loader",
Expand All @@ -24,11 +32,13 @@ exports.askLoader = {
}, {
value: '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',
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 is our convention, check ./applicable.js for acceptable expressions
Expand Down Expand Up @@ -60,7 +70,8 @@ exports.askPlatform = {
}, {
value: 'dotnet-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 = {
message: 'What css processor would you like to use?',
message: 'What css preprocessor would you like to use?',
choices: [{
value: 'none',
message: 'None',
Expand Down Expand Up @@ -206,7 +217,7 @@ exports.askPluginScaffold = {
choices: [{
value: 'plugin-scaffold-minimum',
message: 'None',
hint: 'Just a bare minimum Aurelia plugin.'
hint: 'Just a bare minimum Aurelia plugin with one custom element.'
}, {
value: 'plugin-scaffold-basic',
message: 'Basic',
Expand Down
74 changes: 37 additions & 37 deletions lib/workflow/select-features.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const _ = require('lodash');
const runQuestionnaire = require('./run-questionnaire');
const {
pickPlugin,
askBundler,
askLoader,
askHttp,
Expand Down Expand Up @@ -43,9 +43,6 @@ module.exports = async function(preselectedFeatures = [], opts = {}, _debug = []
if (flow === 'app') {
features = await appFlow(features, flowUnattended, _debug);
} 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);
} else {
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-typescript': {flow: 'app', recommendedFeatures: ['jest', 'typescript', 'vscode'], unattended: true},
'custom-app': {flow: 'app'},
'default-plugin-esnext': {flow: 'plugin', recommendedFeatures: ['cli-bundler', 'requirejs', 'jest', 'vscode'], unattended: true},
'default-plugin-typescript': {flow: 'plugin', recommendedFeatures: ['cli-bundler', 'requirejs', 'jest', 'typescript', 'vscode'], unattended: true},
'custom-plugin': {flow: 'plugin', recommendedFeatures: ['cli-bundler', 'requirejs']}
'default-plugin-esnext': {flow: 'plugin', recommendedFeatures: ['jest', 'vscode'], unattended: true},
'default-plugin-typescript': {flow: 'plugin', recommendedFeatures: ['jest', 'typescript', 'vscode'], unattended: true},
'custom-plugin': {flow: 'plugin'}
};

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

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

async function pluginFlow(features, unattended, _debug) {
return await runQuestionnaire(features, [
pickPlugin,
askBundler,
askLoader,
askPlatform,
askTranspiler,
askMarkupProcessor,
askCssProcessor,
Expand Down
2 changes: 2 additions & 0 deletions skeleton/cli-bundler/README.md
Original file line number Diff line number Diff line change
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`
// @endif

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

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

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

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

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

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

// @if feat.stylus
"source": "src/**/*.styl"
"source": [
// @if feat.plugin
"dev-app/**/*.styl",
// @endif
"src/**/*.styl"
],
// @endif
},
"jsonProcessor": {
"source": "src/**/*.json"
"source": [
// @if feat.plugin
"dev-app/**/*.json",
// @endif
"src/**/*.json"
],
},
// @if feat.karma
"unitTestRunner": {
Expand Down
33 changes: 33 additions & 0 deletions skeleton/cli-bundler/aurelia_project/tasks/process-css.ext
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,36 @@ export default function processCSS() {
// @endif
.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
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,12 @@ export default function processJson() {
return gulp.src(project.jsonProcessor.source, {since: gulp.lastRun(processJson)})
.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
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,28 @@ export default function processMarkup() {
// @endif
.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
Loading

0 comments on commit f5b2367

Please sign in to comment.