Skip to content

Commit

Permalink
Webpack-CLI version 1 (#105)
Browse files Browse the repository at this point in the history
* feat: initial commit on last structure and transforms

* feat: ast for entry

* feat: ast for output

* feat: ast for context

* feat: work in progress on resolve

* feat: add transform structure for all

* fix: remove rx from the project

* fix: return ast on no prop at resolve

* feat: ast for resolve

* feat: ast for devtool

* feat: art  for target

* feat: ast for watch

* feat: sat for watchOptions

* fix: rename dev-tool to devtool

* feat: ast for externals

* feat: ast for node

* feat: sat for performance

* feat: ast for stats

* feat: ast for other

* feat: allow multiple packages in CLI command

* feat: allow dynamic entry points

* feat: allow promises as entry points

* feat: function decl for resolve.cachePredictate

* feat: allow function for performance.assetFilter

* feat: allow regex and functions in external prop

* feat: regexp for outputPrefix

* feat: use property without strings

* feat: allow regex for unsafeCache

* feat: ast for module

* feat: ast for plugins

* feat: art for paths

* feat: prettier, topScope and runtime flow

Adds the runtime flow, with prettier as well as some fixes to
transformations + a top scope transformation.

* feat: ast for cache

* feat: module regexp fix

* feat: fix generator methods

* chore: bump add ons dep

* feat: introduce scaffold for external runs

* feat: don't use jscodeshift to parse unknown values

* feat: allow name conventions

* feat: allow multiple config creations

* feat: allow using inject for resolve and module

* feat: allow merge in scaffold

* fix: make build more readable

* feat: add HOC to each transform

* feat: find correct folder for packages

* fix: example transform in generator and fix to path

* Add your first test (#114)

* Tests for entry.js (#115)

* Add failing test

* Pass the test on entry with array and update snapshots

* If entry is an object

* Add failing test case for externals

* Fix bug with externals regexp

* fix: add identifier creation and fix entry tests

* Add more tests (#116)

* Test watch transform

* Test watch transform (Doesnt look for existing obj)

* Test target transform (Doesnt look for existing obj)

* Test plugins transform (Doesnt look for existing obj)

* Add failing test case for node

* Add test case for node

* Add first instance of duplicate check and override

* Extract a function

* Make a util to override object params

* Cleanup the ast branch transformation (#117)

* refactor watch options

* refactor target

* refactor context

* refactor devtool

* refactor node

* refactor plugins

* refactor amd

* refactor bail

* Moar tests

* feat: add new tests for entry & regex for validateOptions

* feat: more tests for obj ref

Adds more tests to object references and the context transform

* fix: fix devtool property and add tests for it

* add externals test and fix identifier util

Adds tests to externals, some fixes to the externals transform as well
as a fix to utils, where it becomes a literal despite being an
identifier.

* feat: add test to array with obj reference in ext

* fix: fix silly mistake on devtools props

Sorry Pavithra..

* tests: add tests for every transform

* feat: add more utility for tests

* enhancements: use abstractions & utils

* utils: add regex util

* chore: add JSdocs to each transform

* enhancements: use more utility on transforms

* enhancements: use createpushval for all transforms

* enhancements: use new utility to create single properties

* enhancements: add test for utility functions

* fix: don't use await for promise

* enhancements: send each transform object to respective transform

* enhancements: remove createsingular

Replaced by pushCreateProperty

* enhancements: use more utility and remove boilerplate code

* chore: remove fixme flag

* chore: prettify ast.find

* enhancements: use objKey util for entry and externals

* enhancements: use utility on resolve

* enhancements: fix merge & utilize module folder

* enhancements: use prettier node API

* fix: don't print success msg more than one time

* enhancements: fix windows paths

* Webpack-CLI Documentation (#112)

* chore: init

* chore: add section about init and migrate

* chore: add migrate and scaffold link

* Create SCAFFOLDING.md

* Create MIGRATE.md

* chore: add docs on scaffolding

* chore: add initial on addons

* chore: fix initial documentation

Also fixes some text at «Scaffolding»

* chore: revise section on good scaffold

* chore: add some API docs

* chore: rephrase docs

* chore: syntax sugar

* chore: more syntax sugar

* chore: lint webpack-cli properly

* chore: prepare to update webpack/bin to ours

* chore: refactor against webpack/lib

* remove shebang

* chore: remove old rx code

* enhancements: default generator and exitCode

Introduces a default generator and swapped exitCode(0) with exitCode =

* chore: update addons pkg and reformat extractAnswer

* enhancements: better bin resolves & default generator

Thanks to Sindre Sorhus & Addy Osmani for the review. Fixed some better
resolves in bin folder, removed some code in default generator to
better scaffold for beginners.

* enhancements: use validation to force answers

* enhancements: check identifiers with properties

* enhancements: revise anti pattern for promise

Thanks to Sindre Sørhus for this fix. Object references are now making
sure our callbacks are held, and removed the return of the promise and
rather used the object we want to return.

* enhancements: rename write to type and split params to newline

* enhancements: add better scaffold to generator

* enhancements: make default generator more User Friendly

* enhancements: ask if user wants to make the config at end

* enhancements: make default generator better

* enhancements: add styling option to generator

* fix: remove sourceMap from postcss prop

* enhancements: separate dev and prod build

* enhancements: add contentHash & name

* enhancements: prompt for better answers

* fix: remove unused module

* chore: final fixes before release
  • Loading branch information
evenstensberg authored May 7, 2017
1 parent 66280b9 commit 302200d
Show file tree
Hide file tree
Showing 104 changed files with 3,316 additions and 241 deletions.
1 change: 1 addition & 0 deletions MIGRATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,22 @@

# Webpack CLI

This project intends to be the main cli package of webpack. Here we will encapsulate all the features and code related to the command line. From sending options to the compiler, to initialize and migrate from version to version.
Webpack CLI encapsulates all code related to CLI handling. It captures options and sends them to webpack compiler. You can also find functionality for initializing a project and migrating between versions. For the time being, it is backwards-compatible with the CLI included in webpack itself.

**Note** The package is still in work in progress. In case you want to contribute, reach to us, so we can point you out how and when you can help us.

## Migration from webpack v1 to v2

# Roadmap to the first release
The `migrate` feature eases the transition from [version 1](http://webpack.github.io/docs/) to [version 2](https://gist.github.com/sokra/27b24881210b56bbaff7). `migrate` also allows users to switch to the new version of webpack without having to extensively [refactor](https://webpack.js.org/guides/migrating/).

- Migrate to webpack-cli all the current cli options available in webpack
- Create a `webpack-cli init` command that serves to set a configuration of webpack to the user
- create a `webpack-cli migrate` command that serves to migrate an existing configuration from webpack 1 to webpack 2.
`webpack-cli --migrate <config>`

[Read more about migrating](MIGRATE.md)

## Creating new webpack projects

The `init` feature allows users to get started with webpack, fast. Through scaffolding, people can create their own configuration in order to faster initialize new projects for various of use cases.

`webpack-cli --init [webpack-addons-<package>]`

[Read more about scaffolding](SCAFFOLDING.md)
83 changes: 83 additions & 0 deletions SCAFFOLDING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Introduction

Setting up webpack for the first time is hard. Writing advanced configurations to optimize performance is even harder. The `init` feature is designed to support people that want to create their own configuration or initializing other projects people create.

Through [yeoman](http://yeoman.io/), the `webpack-cli --init` feature allows people to create scaffolds and generate new projects quickly. An npm dependency that scaffolds a `webpack.config.js` through `webpack-cli` is what we refer to as an **addon**.

## Writing a good scaffold

Before writing a `webpack-cli` scaffold, think about what you're trying to achieve. Do you want a "general" scaffold that could be used by any project or type of app? Do you want something very focused - like a scaffold that writes both your `webpack.config.js` and your framework code? It's also useful to think about the user experience for your scaffold.

`webpack-cli` offers an experience that is interactive and you can prompt users for questions (like, "What is your entry point?") to help customize the output accordingly.

## webpack-addons

[`webpack-addons`](https://github.com/webpack-contrib/webpack-addons) is a utility suite for creating addons. It contains functions that could be of use for creating an addon yourself.

## webpack-addons-yourpackage

In order for `webpack-cli` to compile your package, it relies on a prefix of `webpack-addons`. The package must also be published on npm. If you are curious about how you can create your very own `addon`, please read [How do I compose a webpack-addon?](https://github.com/ev1stensberg/webpack-addons-demo).

## API

To create an `addon`, you must create a [`yeoman-generator`](http://yeoman.io/authoring/). Because of that, you can optionally extend your generator to include methods from the [Yeoman API](http://yeoman.io/learning/). Its worth noting that we support all the properties of a regular webpack configuration. In order for us to do this, there's a thing you need to remember.

Objects are made using strings, while strings are made using double strings. This means that in order for you to create an string, you have to wrap it inside another string for us to validate it correctly.


### `opts.env.configuration`(Required)

Initialized inside the constructor of your generator in order for the CLI to work.

```js
constructor(args, opts) {
super(args, opts);
opts.env.configuration = {};
}
```
### `opts.env.configuration.myObj` (required)

`myObj` is your scaffold. This is where you will add options for the CLI to transform into a configuration. You can name it anything, and you can also add more objects, that could represent a `dev.config` or `prod.config`.

```js
constructor(args, opts) {
super(args, opts);
opts.env.configuration = {
dev: {},
prod: {}
};
}
```

### `myObj.webpackOptions` (required)

As with a regular webpack configuration, this property behaves the same. Inside `webpackOptions` you can declare the properties you want to scaffold. You can for instance, scaffold `entry`, `output` and `context`.

(Inside a yeoman method)
```js
this.options.env.configuration.dev.webpackOptions = {
entry: '\'app.js\'',
output: {....},
merge: 'myConfig'
};
```
If you want to use `webpack-merge`, you can supply `webpackOptions` with the merge property, and the configuration you want to merge it with.

### `myObj.topScope`(optional)

The `topScope` property is a way for the authors to add special behaviours, like functions that could be called inside a configuration, or variable initializations and module imports.

```js
this.options.env.configuration.dev.topScope = [
'var webpack = require(\'webpack\');'
'var path = require(\'path\');'
];
```

### `myObj.configName`(optional)

If you want to name your `webpack.config.js` something special, you can do that.

```js
this.options.env.configuration.dev.configName = 'base';
```
12 changes: 3 additions & 9 deletions bin/config-yargs.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ module.exports = function(yargs) {
requiresArg: true
},
'env': {
describe: 'Enviroment passed to the config, when it is a function',
describe: 'Environment passed to the config, when it is a function',
group: CONFIG_GROUP
},
'context': {
Expand Down Expand Up @@ -149,7 +149,7 @@ module.exports = function(yargs) {
},
'target': {
type: 'string',
describe: 'The targeted execution enviroment',
describe: 'The targeted execution environment',
group: ADVANCED_GROUP,
requiresArg: true
},
Expand All @@ -166,12 +166,6 @@ module.exports = function(yargs) {
describe: 'Watch the filesystem for changes',
group: BASIC_GROUP
},
'save': {
type: 'boolean',
alias: 's',
describe: 'Rebuilds on save regardless of changes in watch mode',
group: BASIC_GROUP
},
'watch-stdin': {
type: 'boolean',
alias: 'stdin',
Expand All @@ -185,7 +179,7 @@ module.exports = function(yargs) {
},
'watch-poll': {
type: 'boolean',
describe: 'The polling intervall for watching (also enable polling)',
describe: 'The polling interval for watching (also enable polling)',
group: ADVANCED_GROUP
},
'hot': {
Expand Down
43 changes: 18 additions & 25 deletions bin/convert-argv.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ module.exports = function(yargs, argv, convertOptions) {
function processConfiguredOptions(options) {
if(options === null || typeof options !== 'object') {
console.error('Config did not export an object or a function returning an object.');
process.exit(-1);
process.exitCode = -1;
}

// process Promise
Expand Down Expand Up @@ -224,16 +224,10 @@ module.exports = function(yargs, argv, convertOptions) {
options[optionName || name] = false;
});
}
//eslint-disable-next-line
function mapArgToPath(name, optionName) {
ifArg(name, function(str) {
options[optionName || name] = path.resolve(str);
});
}

function loadPlugin(name) {
var loadUtils = require('loader-utils');
var args = null;
var args;
try {
var p = name && name.indexOf('?');
if(p > -1) {
Expand All @@ -242,7 +236,7 @@ module.exports = function(yargs, argv, convertOptions) {
}
} catch(e) {
console.log('Invalid plugin arguments ' + name + ' (' + e + ').');
process.exit(-1);
process.exitCode = -1;
}

var path;
Expand All @@ -251,7 +245,7 @@ module.exports = function(yargs, argv, convertOptions) {
path = resolve.sync(process.cwd(), name);
} catch(e) {
console.log('Cannot resolve plugin ' + name + '.');
process.exit(-1);
process.exitCode = -1;
}
var Plugin;
try {
Expand Down Expand Up @@ -281,7 +275,11 @@ module.exports = function(yargs, argv, convertOptions) {
}

ifArgPair('entry', function(name, entry) {
options.entry[name] = entry;
if(typeof options.entry[name] !== 'undefined' && options.entry[name] !== null) {
options.entry[name] = [].concat(options.entry[name]).concat(entry);
} else {
options.entry[name] = entry;
}
}, function() {
ensureObject(options, 'entry');
});
Expand Down Expand Up @@ -322,7 +320,7 @@ module.exports = function(yargs, argv, convertOptions) {

ifArg('output-path', function(value) {
ensureObject(options, 'output');
options.output.path = value;
options.output.path = path.resolve(value);
});

ifArg('output-filename', function(value) {
Expand Down Expand Up @@ -454,7 +452,7 @@ module.exports = function(yargs, argv, convertOptions) {

ifArg('prefetch', function(request) {
ensureArray(options, 'plugins');
var PrefetchPlugin = require('webpack/PrefetchPlugin');
var PrefetchPlugin = require('webpack/lib/PrefetchPlugin');
options.plugins.push(new PrefetchPlugin(request));
});

Expand All @@ -468,16 +466,10 @@ module.exports = function(yargs, argv, convertOptions) {
} else {
name = value;
}
var ProvidePlugin = require('webpack/ProvidePlugin');
var ProvidePlugin = require('webpack/lib/ProvidePlugin');
options.plugins.push(new ProvidePlugin(name, value));
});

ifBooleanArg('labeled-modules', function() {
ensureArray(options, 'plugins');
var LabeledModulesPlugin = require('webpack/lib/dependencies/LabeledModulesPlugin');
options.plugins.push(new LabeledModulesPlugin());
});

ifArg('plugin', function(value) {
ensureArray(options, 'plugins');
options.plugins.push(loadPlugin(value));
Expand All @@ -490,19 +482,20 @@ module.exports = function(yargs, argv, convertOptions) {
if(noOutputFilenameDefined) {
ensureObject(options, 'output');
if(convertOptions && convertOptions.outputFilename) {
options.output.path = path.dirname(convertOptions.outputFilename);
options.output.path = path.resolve(path.dirname(convertOptions.outputFilename));
options.output.filename = path.basename(convertOptions.outputFilename);
} else if(argv._.length > 0) {
options.output.filename = argv._.pop();
options.output.path = path.dirname(options.output.filename);
options.output.path = path.resolve(path.dirname(options.output.filename));
options.output.filename = path.basename(options.output.filename);
} else if(configFileLoaded) {
throw new Error('\'output.filename\' is required, either in config file or as --output-filename');
} else {
}
else {
console.error('No configuration file found and no output filename configured via CLI option.');
console.error('A configuration file could be named \'webpack.config.js\' in the current directory.');
console.error('Use --help to display the CLI options.');
process.exit(-1);
process.exitCode = -1;
}
}

Expand Down Expand Up @@ -549,7 +542,7 @@ module.exports = function(yargs, argv, convertOptions) {
console.error('A configuration file could be named \'webpack.config.js\' in the current directory.');
}
console.error('Use --help to display the CLI options.');
process.exit(-1);
process.exitCode = -1;
}
}
};
8 changes: 4 additions & 4 deletions bin/process-options.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ module.exports = function processOptions(yargs, argv) {
console.error('\u001b[1m\u001b[31m' + e.message + '\u001b[39m\u001b[22m');
else
console.error(e.message);
process.exit(1);
process.exitCode = 1;
}
throw e;
}
Expand All @@ -160,7 +160,7 @@ module.exports = function processOptions(yargs, argv) {
lastHash = null;
console.error(err.stack || err);
if(err.details) console.error(err.details);
process.exit(1);
process.exitCode = 1;
}
if(outputOptions.json) {
process.stdout.write(JSON.stringify(stats.toJson(outputOptions), null, 2) + '\n');
Expand All @@ -172,7 +172,7 @@ module.exports = function processOptions(yargs, argv) {
}
if(!options.watch && stats.hasErrors()) {
process.on('exit', function() {
process.exit(2);
process.exitCode = 2;
});
}
}
Expand All @@ -181,7 +181,7 @@ module.exports = function processOptions(yargs, argv) {
var watchOptions = primaryOptions.watchOptions || primaryOptions.watch || {};
if(watchOptions.stdin) {
process.stdin.on('end', function() {
process.exit(0);
process.exitCode = 0;
});
process.stdin.resume();
}
Expand Down
Loading

0 comments on commit 302200d

Please sign in to comment.