Skip to content
Permalink
Browse files

feat: scaffolding aurelia plugin project

supersedes #793, closes #658
  • Loading branch information...
huochunpeng committed Mar 20, 2019
1 parent 71504b5 commit f5b2367a960b90f47766980cedda4b033ab0c3fd
Showing with 925 additions and 63 deletions.
  1. +7 −2 lib/commands/new/command.js
  2. +5 −0 lib/commands/new/command.json
  3. +7 −3 lib/workflow/applicable.js
  4. +17 −6 lib/workflow/questionnaire.js
  5. +37 −37 lib/workflow/select-features.js
  6. +2 −0 skeleton/cli-bundler/README.md
  7. +49 −8 skeleton/cli-bundler/aurelia_project/aurelia.json
  8. +33 −0 skeleton/cli-bundler/aurelia_project/tasks/process-css.ext
  9. +9 −0 skeleton/cli-bundler/aurelia_project/tasks/process-json.ext
  10. +25 −0 skeleton/cli-bundler/aurelia_project/tasks/process-markup.ext
  11. +19 −0 skeleton/cli-bundler/aurelia_project/tasks__if_babel/transpile.js
  12. +16 −0 skeleton/cli-bundler/aurelia_project/tasks__if_typescript/transpile.ts
  13. +6 −0 skeleton/common/package.json
  14. 0 skeleton/common/src/{environment.ext → environment.ext__if_not_plugin}
  15. +3 −0 skeleton/common/tsconfig.json__if_typescript
  16. +6 −1 skeleton/jest/package.json
  17. +1 −0 skeleton/jest/test__if_cli-bundler/mock-css.js__if_less_or_sass_or_stylus
  18. +127 −0 skeleton/plugin/README.md
  19. +41 −0 skeleton/plugin/aurelia_project/aurelia.json
  20. +33 −0 skeleton/plugin/aurelia_project/tasks/build-plugin.ext
  21. +13 −0 skeleton/plugin/dev-app/app.ext
  22. +29 −0 skeleton/plugin/dev-app/app.html
  23. +4 −0 skeleton/plugin/dev-app/environment.ext
  24. +24 −0 skeleton/plugin/dev-app/main.ext
  25. +22 −0 skeleton/plugin/package.json
  26. +12 −0 skeleton/plugin/src/attributes__if_plugin-scaffold-basic/color.js__if_babel
  27. +10 −0 skeleton/plugin/src/attributes__if_plugin-scaffold-basic/color.ts__if_typescript
  28. +21 −0 skeleton/plugin/src/binding-behaviors__if_plugin-scaffold-basic/primary-click.ext
  29. +3 −0 skeleton/plugin/src/elements/hello-world.css__if_not_less_and_not_sass_and_not_stylus
  30. +10 −0 skeleton/plugin/src/elements/hello-world.ext
  31. +4 −0 skeleton/plugin/src/elements/hello-world.html
  32. +3 −0 skeleton/plugin/src/elements/hello-world.less__if_less
  33. +3 −0 skeleton/plugin/src/elements/hello-world.scss__if_sass
  34. +2 −0 skeleton/plugin/src/elements/hello-world.styl__if_stylus
  35. +15 −0 skeleton/plugin/src/index.ext
  36. +10 −0 skeleton/plugin/src/value-converters__if_plugin-scaffold-basic/upcase.ext
  37. +5 −0 skeleton/plugin/test__if_karma_or_jest/unit/.eslintrc__if_babel
  38. +36 −0 skeleton/plugin/test__if_karma_or_jest/unit/attributes__if_plugin-scaffold-basic/color.spec.ext
  39. +63 −0 ...in/test__if_karma_or_jest/unit/binding-behaviors__if_plugin-scaffold-basic/primary-click.spec.ext
  40. +36 −0 skeleton/plugin/test__if_karma_or_jest/unit/elements/hello-world.spec.ext
  41. +23 −0 ...ton/plugin/test__if_karma_or_jest/unit/value-converters__if_plugin-scaffold-basic/upcase.spec.ext
  42. +134 −6 spec/lib/workflow/select-features.spec.js
@@ -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!`);
@@ -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.",
@@ -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}`);
}
};
@@ -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",
@@ -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
@@ -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'
}]
};

@@ -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',
@@ -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',
@@ -1,6 +1,6 @@
const _ = require('lodash');
const runQuestionnaire = require('./run-questionnaire');
const {
pickPlugin,
askBundler,
askLoader,
askHttp,
@@ -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.`);
@@ -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) {
@@ -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];
@@ -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,
@@ -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
@@ -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": {
@@ -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
@@ -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
@@ -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
Oops, something went wrong.

0 comments on commit f5b2367

Please sign in to comment.
You can’t perform that action at this time.