mirror of
https://github.com/wassname/generator-react-webpack.git
synced 2026-08-30 11:23:47 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ee10ffd52 | ||
|
|
60bf2aae3a | ||
|
|
cb98c7e528 | ||
|
|
498c1032f2 | ||
|
|
20cbcee3fe | ||
|
|
e74b89d8ea | ||
|
|
4e2650f244 | ||
|
|
c99d3c6682 | ||
|
|
9c40789c96 | ||
|
|
fe4d214be9 | ||
|
|
492d2c6947 | ||
|
|
b214930f8e | ||
|
|
4596462f29 | ||
|
|
0e3b554855 | ||
|
|
98ffadd612 | ||
|
|
629ce71db5 | ||
|
|
3a10311c47 | ||
|
|
255d7b94d8 | ||
|
|
ac6eb05171 | ||
|
|
9f427d9332 | ||
|
|
003f8ce8e6 | ||
|
|
aa468d529d | ||
|
|
62b36813b3 | ||
|
|
e7501dccbd | ||
|
|
f70a1eed8f | ||
|
|
312c88b0bc | ||
|
|
7d01c86522 | ||
|
|
fffd03bfa3 | ||
|
|
d2992321e8 | ||
|
|
c897085128 | ||
|
|
5eee756f3e | ||
|
|
91ac75db71 | ||
|
|
25c67ffd33 | ||
|
|
8cdcc2c432 | ||
|
|
cee53ad6c1 | ||
|
|
ad6135e48d | ||
|
|
63f1b74fe7 | ||
|
|
432d5d00de | ||
|
|
685f6a75ce | ||
|
|
82a080f586 | ||
|
|
6c41164d4a | ||
|
|
9eedc6fd2f | ||
|
|
83d47bddd8 | ||
|
|
31e478f28d | ||
|
|
b95fc4344a | ||
|
|
66b85f48d8 | ||
|
|
bf2df82159 | ||
|
|
d729c3caa8 | ||
|
|
4f99a5a9db | ||
|
|
190cfdac06 | ||
|
|
ca3f923bf0 | ||
|
|
57a2ac9325 | ||
|
|
de5cca9866 | ||
|
|
4e8d7af872 | ||
|
|
85470145f5 | ||
|
|
520db61333 | ||
|
|
260758f93b | ||
|
|
361ea7409d | ||
|
|
47f1273828 | ||
|
|
56ff5c6281 | ||
|
|
7269a0a315 | ||
|
|
6a3da576fa | ||
|
|
e7bbcb1fe7 | ||
|
|
8a2fc142ba | ||
|
|
76f0e8e672 | ||
|
|
a5c4ea4c74 | ||
|
|
9c61be0c24 | ||
|
|
6516861e79 | ||
|
|
023d937877 |
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": false,
|
||||
"amd": false,
|
||||
"es6": true,
|
||||
"node": true,
|
||||
"mocha": true
|
||||
},
|
||||
"rules": {
|
||||
"comma-dangle": 1,
|
||||
"quotes": [ 1, "single" ],
|
||||
"no-undef": 1,
|
||||
"global-strict": 0,
|
||||
"no-extra-semi": 1,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-console": 0,
|
||||
"no-unused-vars": 1,
|
||||
"no-trailing-spaces": [1, { "skipBlankLines": true }],
|
||||
"no-unreachable": 1,
|
||||
"no-alert": 0
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -13,4 +13,4 @@ $RECYCLE.BIN/
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
.idea/
|
||||
/test/temp-test
|
||||
test/temp-test
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"node": true,
|
||||
"esnext": true,
|
||||
"bitwise": true,
|
||||
"camelcase": true,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"immed": true,
|
||||
"indent": 2,
|
||||
"latedef": true,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"quotmark": "single",
|
||||
"regexp": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"strict": true,
|
||||
"trailing": true,
|
||||
"smarttabs": true,
|
||||
"white": true
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '0.10'
|
||||
- '4.2.2'
|
||||
before_install:
|
||||
- currentfolder=${PWD##*/}
|
||||
- if [ "$currentfolder" != 'generator-react-webpack' ]; then cd .. && eval "mv $currentfolder generator-react-webpack" && cd generator-react-webpack; fi
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# generator-react-webpack - Changelog
|
||||
|
||||
## 3.1.2
|
||||
|
||||
1. Updated yeoman-generator package to new version 0.22.1 (some methods like generator.NamedBase are now deprecated!)
|
||||
|
||||
## 3.1.1
|
||||
|
||||
1. Added bugfix for https://github.com/newtriks/generator-react-webpack/issues/170
|
||||
|
||||
## 3.1.0
|
||||
|
||||
1. Added support for postcss (Patch provided by [stylesuxx](https://github.com/stylesuxx))
|
||||
|
||||
## 3.0.1
|
||||
|
||||
1. Unneeded files (License, .npmignore) are not copied anymore
|
||||
2. Existence of .babelrc is now checked in unit tests
|
||||
|
||||
## 3.0.0
|
||||
|
||||
1. Updated react-webpack-template to 1.0.0 to include support for babel 6.
|
||||
|
||||
## 2.2.7
|
||||
|
||||
1. Updated yeoman to 0.21
|
||||
2. Added some badges for the readme
|
||||
|
||||
## 2.2.6
|
||||
|
||||
1. Added new version of ```react-webpack-template``` (provides new features for continuous testing and better dist build support)
|
||||
|
||||
## 2.2.5
|
||||
|
||||
1. Added ability to create stateless components
|
||||
2. Updated README with new installation instructions (need to install globally)
|
||||
3. Added new tests for components (should be easier to handle in the future)
|
||||
|
||||
## 2.2.4
|
||||
|
||||
1. Added automatic generation of components displayName property. This makes it easier to keep track of components that reside in deep subfolders (like src/components/my/example/components/indexComponent) would become "index" as a displayName, but should instead be MyExampleComponentsIndexComponent instead.
|
||||
|
||||
## 2.2.3
|
||||
|
||||
1. Fixed .gitignore renaming (Patch provided by [VovanR](https://github.com/VovanR))
|
||||
|
||||
## 2.2.0:
|
||||
|
||||
1. Added new version of react-webpack-template, including support for React 0.14.
|
||||
@@ -1,405 +1,132 @@
|
||||
# generator-react-webpack [](https://travis-ci.org/newtriks/generator-react-webpack) [](http://gruntjs.com/)
|
||||
# generator-react-webpack V2.0
|
||||
|
||||
[](https://travis-ci.org/newtriks/generator-react-webpack) [](https://bitdeli.com/free "Bitdeli Badge")    
|
||||
|
||||
> Yeoman generator for [ReactJS](http://facebook.github.io/react/) - lets you quickly set up a project including karma test runner and [Webpack](http://webpack.github.io/) module system.
|
||||
|
||||
# About
|
||||
Generator-React-Webpack will help you build new React projects using modern technologies.
|
||||
|
||||
## Usage
|
||||
Out of the box it comes with support for:
|
||||
- Webpack
|
||||
- ES2015 via Babel-Loader
|
||||
- Different supported style languages (sass, scss, less, stylus)
|
||||
- Style transformations via PostCSS
|
||||
- Automatic code linting via esLint
|
||||
- Ability to unit test components via Karma and Mocha/Chai
|
||||
|
||||
Install `generator-react-webpack`:
|
||||
```
|
||||
## Changes in Version 2.0
|
||||
This generator is written in ES2015. This means it is ___not compatible with node.js versions before 4.0___.
|
||||
|
||||
It also does __NOT__ include support for Flux-Frameworks anymore. Instead, we will use it as a base for other generators to build upon. This will make the base generator easier to use and update.
|
||||
|
||||
If you are interested, feel free to write your own generator and use generator-react-webpack as a base (via composition).
|
||||
|
||||
If you have built a generator using generator-react-webpack, tell us and we will add a link to our README.
|
||||
|
||||
## Generators that extend generator-react-webpack
|
||||
- [Generator-React-Webpack-Alt](https://github.com/weblogixx/generator-react-webpack-alt) (Adds ability to create actions, stores and sources for [alt.js](http://alt.js.org))
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
# Make sure both is installed globally
|
||||
npm install -g yo
|
||||
npm install -g generator-react-webpack
|
||||
```
|
||||
|
||||
Make a new directory, and `cd` into it:
|
||||
```
|
||||
mkdir my-new-project && cd $_
|
||||
```
|
||||
|
||||
Run `yo react-webpack`, optionally passing an app name:
|
||||
```
|
||||
yo react-webpack [app-name]
|
||||
```
|
||||
|
||||
Run `grunt build` for building and `grunt serve` for preview in the browser at [localhost](http://localhost:8000).
|
||||
|
||||
## Generators
|
||||
|
||||
Available generators:
|
||||
|
||||
* [react-webpack](#app) (aka [react-webpack:app](#app))
|
||||
* [react-webpack:component](#component)
|
||||
|
||||
and for **Flux** or **Reflux** :
|
||||
* [react-webpack:action](#action)
|
||||
* [react-webpack:store](#store)
|
||||
|
||||
|
||||
### App
|
||||
|
||||
Sets up a new ReactJS app, generating all the boilerplate you need to get started. The app generator also facilitates the following:
|
||||
|
||||
1. Configures a Gruntfile to run the app on a local server.
|
||||
2. Configures Webpack to modularise the app enabling [loading of various file formats](http://webpack.github.io/docs/loader-list.html) e.g. JSON, CSS, PNG, etc.
|
||||
3. Configures [Karma](http://karma-runner.github.io) to run all tests.
|
||||
4. Watches for changes and recompiles JS and refreshes the browser.
|
||||
|
||||
Example:
|
||||
## Setting up projects
|
||||
```bash
|
||||
# Create a new directory, and `cd` into it:
|
||||
mkdir my-new-project && cd my-new-project
|
||||
|
||||
# Run the generator
|
||||
yo react-webpack
|
||||
```
|
||||
|
||||
### Component
|
||||
Please make sure to edit your newly generated `package.json` file to set description, author information and the like.
|
||||
|
||||
Generates a [JSX](http://facebook.github.io/react/docs/jsx-in-depth.html) component in `src/components`, its corresponding test in `test/spec/components` and its style in `src/styles`.
|
||||
|
||||
Example:
|
||||
## Generating new components
|
||||
```bash
|
||||
yo react-webpack:component foo //or just: yo react-webpack:c foo
|
||||
# After setup of course :)
|
||||
# cd my-new-project
|
||||
yo react-webpack:component my/namespaced/components/name
|
||||
```
|
||||
|
||||
Produces `src/components/Foo.js` (*javascript - JSX*):
|
||||
```js
|
||||
'use strict';
|
||||
The above command will create a new component, as well as its stylesheet and a basic testcase.
|
||||
|
||||
var React = require('react/addons');
|
||||
|
||||
require('styles/componentName.css'); //or .sass,.less etc...
|
||||
|
||||
var Foo = React.createClass({
|
||||
render: function () {
|
||||
return (
|
||||
<div>
|
||||
<p>Content for Foo</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Foo;
|
||||
## Generating new stateless functional components
|
||||
```
|
||||
yo react-webpack:component my/namespaced/components/name --stateless
|
||||
```
|
||||
|
||||
And `test/spec/components/Foo.js` (*javascript - jasmine, as seen on http://simonsmith.io/unit-testing-react-components-without-a-dom/*):
|
||||
```js
|
||||
'use strict';
|
||||
Stateless functional components where introduced in React v0.14. They have a much shorter syntax than regular ones and no state or lifecycle methods at all. Please read the [React 0.14 release notes](https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html) to get more information about those components.
|
||||
|
||||
// Uncomment the following lines to use the react test utilities
|
||||
// import React from 'react/addons';
|
||||
// const TestUtils = React.addons.TestUtils;
|
||||
___Note___: You will still be able to set properties for stateless components!
|
||||
|
||||
import createComponent from 'helpers/createComponent';
|
||||
import Foo from 'components/Foo.js';
|
||||
## Adding PostCSS plugins
|
||||
If you have enabled [PostCSS](https://github.com/postcss/postcss) at generation time, install your PostCSS plugins via npm and *require* it in **postcss** function in *cfg/base.js*.
|
||||
|
||||
describe('Foo', () => {
|
||||
|
||||
let FooComponent;
|
||||
|
||||
beforeEach(() => {
|
||||
FooComponent = createComponent(Foo);
|
||||
});
|
||||
|
||||
it('should have its component name as default className', () => {
|
||||
expect(FooComponent._store.props.className).toBe('Foo');
|
||||
});
|
||||
});
|
||||
Example for autoprefixer:
|
||||
```bash
|
||||
cd my-new-project
|
||||
npm install autoprefixer
|
||||
```
|
||||
|
||||
And `src/styles/Foo.css` (or .sass, .less etc...) :
|
||||
```css
|
||||
.Foo {
|
||||
border: 1px dashed #f00;
|
||||
Require in *cfg/base.js*
|
||||
```JavaScript
|
||||
...
|
||||
postcss: function () {
|
||||
return [
|
||||
require('autoprefixer')({
|
||||
browsers: ['last 2 versions', 'ie >= 8']
|
||||
})
|
||||
];
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
### rich flag
|
||||
|
||||
For all you lazy programmers out there, we've added another shortcut - `rich` flag:
|
||||
## Usage
|
||||
The following commands are available in your project:
|
||||
```bash
|
||||
yo react-webpack:c foofoo --rich
|
||||
# Start for development
|
||||
npm start # or
|
||||
npm run serve
|
||||
|
||||
# Start the dev-server with the dist version
|
||||
npm run serve:dist
|
||||
|
||||
# Just build the dist version and copy static files
|
||||
npm run dist
|
||||
|
||||
# Run unit tests
|
||||
npm test
|
||||
|
||||
# Lint all files in src (also automatically done AFTER tests are run)
|
||||
npm run lint
|
||||
|
||||
# Clean up the dist directory
|
||||
npm run clean
|
||||
|
||||
# Just copy the static assets
|
||||
npm run copy
|
||||
```
|
||||
This will give you all of react component's most common stuff :
|
||||
```js
|
||||
var React = require('react/addons');
|
||||
|
||||
require('styles/Foofoo.sass');
|
||||
|
||||
var Foofoo = React.createClass({
|
||||
mixins: [],
|
||||
getInitialState: function() {
|
||||
return {};
|
||||
},
|
||||
getDefaultProps: function() {},
|
||||
componentWillMount: function() {},
|
||||
componentDidMount: function() {},
|
||||
shouldComponentUpdate: function() {},
|
||||
componentDidUpdate: function() {},
|
||||
componentWillUnmount: function() {},
|
||||
|
||||
render: function () {
|
||||
return (
|
||||
<div>
|
||||
<p>Content for Foofoo</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Foofoo;
|
||||
```
|
||||
|
||||
Just remove those you don't need, then fill and space out the rest.
|
||||
|
||||
### Action
|
||||
|
||||
When using Flux or Reflux architecture, it generates an actionCreator in `src/actions` and it's corresponding test in `src/spec/actions`.
|
||||
|
||||
Example:
|
||||
```bash
|
||||
yo react-webpack:action bar //or just: yo react-webpack:a bar
|
||||
```
|
||||
Will create a file - `src/actions/BarActionCreators.js`
|
||||
|
||||
if 'architecture' is **Flux**, it Produces :
|
||||
```js
|
||||
'use strict';
|
||||
|
||||
var BarActionCreators = {
|
||||
|
||||
}
|
||||
|
||||
module.exports = BarActionCreators;
|
||||
```
|
||||
And if it's **Reflux**:
|
||||
```js
|
||||
'use strict';
|
||||
|
||||
var Reflux = require('reflux');
|
||||
|
||||
var BarActionCreators = Reflux.createActions([
|
||||
|
||||
]);
|
||||
|
||||
|
||||
module.exports = BarActionCreators;
|
||||
```
|
||||
|
||||
and same test for both architectures:
|
||||
```js
|
||||
'use strict';
|
||||
|
||||
describe('BarActionCreators', () => {
|
||||
let action;
|
||||
|
||||
beforeEach(function() {
|
||||
action = require('actions/BarActionCreators.js');
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(action).toBeDefined();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Store
|
||||
|
||||
When using Flux or Reflux architecture, it generates a store in `src/stores` and it's corresponding test in `src/spec/stores`.
|
||||
|
||||
Example:
|
||||
```bash
|
||||
yo react-webpack:store baz //or just: yo react-webpack:s baz
|
||||
```
|
||||
Will create a file - `src/stores/BazStore.js`
|
||||
|
||||
if 'architecture' is **Flux**, it Produces :
|
||||
```js
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var assign = require('object-assign');
|
||||
var MainAppDispatcher = require('../dispatcher/MainAppDispatcher');
|
||||
|
||||
var BazStore = assign({}, EventEmitter.prototype, {
|
||||
|
||||
});
|
||||
|
||||
BazStore.dispatchToken = MainAppDispatcher.register(function(action) {
|
||||
|
||||
switch(action.type) {
|
||||
default:
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = BazStore;
|
||||
```
|
||||
And if it's **Reflux**:
|
||||
```js
|
||||
'use strict';
|
||||
|
||||
var Reflux = require('reflux');
|
||||
//var Actions = require('actions/..');
|
||||
|
||||
|
||||
var BazStore = Reflux.createStore({
|
||||
listenables: Actions,
|
||||
|
||||
|
||||
});
|
||||
|
||||
module.exports = BazStore;
|
||||
```
|
||||
|
||||
and same test for both architectures:
|
||||
```js
|
||||
'use strict';
|
||||
|
||||
describe('BazStore', () => {
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = require('stores/BazStore.js');
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(store).toBeDefined();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Options
|
||||
Options are available as additional installs to the initial application generation phase.
|
||||
|
||||
### [ReactRouter](https://github.com/rackt/react-router)
|
||||
|
||||
A complete routing library for React. This option only adds the basic hooks to get started with [react router](https://github.com/rackt/react-router).
|
||||
|
||||
### styles language
|
||||
|
||||
css, sass, scss, less or stylus
|
||||
|
||||
Sets the style file's template and extension
|
||||
|
||||
### component suffix
|
||||
|
||||
js or jsx
|
||||
|
||||
Sets the file suffix for generated components. Defaults to "js". Please note that you need to require files *including* the file ending when using jsx as suffix. Example:
|
||||
|
||||
```js
|
||||
var MyJSComponent = require('./MyJSComponent');
|
||||
var MyJSX = require('./MyJSX.jsx');
|
||||
```
|
||||
|
||||
### architecture
|
||||
|
||||
[flux](https://facebook.github.io/flux/) or [reflux](https://github.com/spoike/refluxjs)
|
||||
|
||||
### es6
|
||||
|
||||
If you are using `es6`, and want to use its export functionality (and not webpack's), just add `--es6` flag when you create a component, action or store.
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
Running `grunt test` will run the unit tests with karma. Tests are written using [Jasmine](http://jasmine.github.io/) by default.
|
||||
|
||||
## Further Information
|
||||
|
||||
### Project Structure
|
||||
|
||||
The react-webpack generator automates the setup of a [ReactJS](http://facebook.github.io/react/) project using the specific structure detailed below:
|
||||
|
||||
```
|
||||
project
|
||||
- src
|
||||
-components
|
||||
MainApp.js
|
||||
Foo.js
|
||||
AnotherComponent.js
|
||||
|
||||
//for flux/reflux
|
||||
-actions
|
||||
BarActionCreators.js
|
||||
-stores
|
||||
BazStore.js
|
||||
//for flux
|
||||
-dispatcher
|
||||
FooAppDispatcher
|
||||
|
||||
- styles
|
||||
main.css
|
||||
index.html
|
||||
- test
|
||||
- spec
|
||||
- components
|
||||
MainApp.js
|
||||
Foo.js
|
||||
AnotherComponent.js
|
||||
|
||||
//for flux/reflux
|
||||
-actions
|
||||
BarActionCreators.js
|
||||
-stores
|
||||
BazStore.js
|
||||
|
||||
- helpers
|
||||
- react
|
||||
addons.js
|
||||
phantomjs-shims.js
|
||||
Gruntfile.js
|
||||
karma.conf.js
|
||||
package.json
|
||||
webpack.config.js
|
||||
webpack.dist.config.js
|
||||
```
|
||||
|
||||
I have tried to keep the project structure as simple as possible and understand it may not suit everyone.
|
||||
|
||||
### Naming Components
|
||||
|
||||
I have opted to follow [@floydophone](https://twitter.com/floydophone) convention of uppercase for component file naming e.g. [Component.js](https://github.com/petehunt/ReactHack/tree/master/src/components). I am open to suggestions if there is a general objection to this decision.
|
||||
We have opted to follow [@floydophone](https://twitter.com/floydophone) convention of uppercase for component file naming e.g. [Component.js](https://github.com/petehunt/ReactHack/tree/master/src/components). I am open to suggestions if there is a general objection to this decision.
|
||||
|
||||
### Modules
|
||||
|
||||
Each component is a module and can be required using the [Webpack](http://webpack.github.io/) module system. [Webpack](http://webpack.github.io/) uses [Loaders](http://webpack.github.io/docs/loaders.html) which means you can also require CSS and a host of other file types. Read the [Webpack documentation](http://webpack.github.io/docs/home.html) to find out more.
|
||||
|
||||
### Grunt
|
||||
|
||||
Out the box the [Gruntfile](http://gruntjs.com/api/grunt.file) is configured with the following:
|
||||
|
||||
1. **webpack**: uses the [grunt-webpack](https://github.com/webpack/grunt-webpack) plugin to load all required modules and output to a single JS file `src/main.js`. This is included in the `src/index.html` file by default and will reload in the browser as and when it is recompiled.
|
||||
2. **webpack-dev-server**: uses the [webpack-dev-server](https://github.com/webpack/webpack-dev-server) to watch for file changes and also serve the webpack app in development.
|
||||
3. **connect**: uses the [grunt-connect](https://github.com/gruntjs/grunt-contrib-connect) plugin to start a webserver at [localhost](http://localhost:8000).
|
||||
4. **karma**: uses the [grunt-karma](https://github.com/karma-runner/grunt-karma) plugin to load the Karma configuration file `karma.conf.js` located in the project root. This will run all tests using [PhantomJS](http://phantomjs.org/) by default but supports many other browsers. Please note that karma-launchers other than PhantomJS must be installed separately and configured in `karma.conf.js`.
|
||||
|
||||
### CSS
|
||||
|
||||
Included in the project is the [normalize.css](http://necolas.github.io/normalize.css/) script. There is also a `src/styles/main.css` script that's required by the core `src/components/App.js` component using Webpack.
|
||||
|
||||
### Linting
|
||||
|
||||
Webpack is automatically configured to run esLint (http://eslint.org) on every file change or build. The configuration can be found in `PROJECTROOT/.eslintrc`. There are plugins for different editors that use this tool directly:
|
||||
- linter-eslint for Atom
|
||||
- Sublime-Linter-eslint for Sublime
|
||||
|
||||
You could also use jsxhint, the corresponding rules file is located in `PROJECTROOT/.jshintrc`. However, the support for jsxhint is planned to be dropped in a later release and only available for backwards compatibility.
|
||||
|
||||
## Props
|
||||
|
||||
Thanks to all who contributed to [generator-angular](https://github.com/yeoman/generator-angular) as the majority of code here has been shamelessy sourced from that repos.
|
||||
|
||||
Thanks to [Edd Hannay](https://github.com/eddhannay) for his Webpack optimisations, my local merge and testing meant his additions lost his signature (my fault sorry) so big thanks Edd.
|
||||
Thanks to [Edd Hannay](https://github.com/eddhannay) for his Webpack optimisations, my local merge and testing meant his additions lost his signature (my fault, sorry). So, big thanks Edd.
|
||||
|
||||
## Contribute
|
||||
|
||||
Contributions are welcomed. When submitting a bugfix, write a test that exposes the bug and fails before applying your fix. Submit the test alongside the fix.
|
||||
|
||||
### Running Tests
|
||||
|
||||
`node node_modules/.bin/mocha`
|
||||
`npm test` or `node node_modules/.bin/mocha`
|
||||
|
||||
## License
|
||||
|
||||
[BSD license](http://opensource.org/licenses/bsd-license.php)
|
||||
|
||||
[](https://bitdeli.com/free "Bitdeli Badge")
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require('../action');
|
||||
@@ -1,39 +0,0 @@
|
||||
'use strict';
|
||||
var util = require('util');
|
||||
var ScriptBase = require('../script-base.js');
|
||||
|
||||
var ActionGenerator = module.exports = function ActionGenerator(args, options, config) {
|
||||
if (!args[0]) console.log('\n Please specify a name for this action creator \n');
|
||||
else {
|
||||
args[0] += 'ActionCreators';
|
||||
ScriptBase.apply(this, arguments)
|
||||
}
|
||||
};
|
||||
|
||||
util.inherits(ActionGenerator, ScriptBase);
|
||||
|
||||
ActionGenerator.prototype.createActionFile = function createActionFile() {
|
||||
this.option('es6');
|
||||
this.es6 = this.options.es6;
|
||||
|
||||
var actionTemplate;
|
||||
switch (this.architecture){
|
||||
case 'flux':
|
||||
actionTemplate = 'FluxAction';
|
||||
break;
|
||||
case 'reflux':
|
||||
actionTemplate = 'RefluxAction';
|
||||
break;
|
||||
case 'alt':
|
||||
actionTemplate = 'AltAction';
|
||||
break;
|
||||
}
|
||||
|
||||
console.log('Creating ' + this.architecture + ' action');
|
||||
|
||||
this.generateSourceAndTest(
|
||||
actionTemplate,
|
||||
'spec/Action',
|
||||
'actions'
|
||||
);
|
||||
};
|
||||
-164
@@ -1,164 +0,0 @@
|
||||
'use strict';
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var yeoman = require('yeoman-generator');
|
||||
var generalUtils = require('../util.js');
|
||||
|
||||
var ReactWebpackGenerator = module.exports = function ReactWebpackGenerator(args, options, config) {
|
||||
yeoman.generators.Base.apply(this, arguments);
|
||||
this.option('es6');
|
||||
|
||||
this.argument('appname', { type: String, required: false });
|
||||
this.appname = this.appname || path.basename(process.cwd());
|
||||
this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname)));
|
||||
this.scriptAppName = this._.capitalize(this.appname) + generalUtils.appName(this);
|
||||
|
||||
this.config.set('app-name', this.appname);
|
||||
|
||||
|
||||
if (typeof this.options.appPath === 'undefined') {
|
||||
this.options.appPath = this.options.appPath || 'src';
|
||||
}
|
||||
|
||||
this.appPath = this.options.appPath;
|
||||
|
||||
args = [this.scriptAppName];
|
||||
|
||||
this.composeWith('react-webpack:common', {
|
||||
args: args
|
||||
});
|
||||
|
||||
this.composeWith('react-webpack:main', {
|
||||
args: args
|
||||
});
|
||||
|
||||
this.on('end', function () {
|
||||
this.installDependencies({ skipInstall: options['skip-install'], bower: false });
|
||||
});
|
||||
|
||||
|
||||
this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
|
||||
|
||||
this.config.save();
|
||||
};
|
||||
|
||||
util.inherits(ReactWebpackGenerator, yeoman.generators.Base);
|
||||
|
||||
ReactWebpackGenerator.prototype.welcome = function welcome() {
|
||||
// welcome message
|
||||
if (!this.options['skip-welcome-message']) {
|
||||
console.log(this.yeoman);
|
||||
console.log(
|
||||
'Out of the box I include Webpack and some default React components.\n'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
ReactWebpackGenerator.prototype.askForReactRouter = function () {
|
||||
var done = this.async();
|
||||
this.prompt({
|
||||
type : 'confirm',
|
||||
name : 'reactRouter',
|
||||
message : 'Would you like to include react-router?',
|
||||
default : true
|
||||
}, function (props) {
|
||||
this.env.options.reactRouter = props.reactRouter;
|
||||
done();
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
ReactWebpackGenerator.prototype.askForArchitecture = function() {
|
||||
var done = this.async();
|
||||
this.prompt({
|
||||
type : 'list',
|
||||
name : 'architecture',
|
||||
message : 'Would you like to use one of these architectures?',
|
||||
choices: [
|
||||
{name:'No need for that, thanks',value:false},
|
||||
{name:'Flux',value:'flux'},
|
||||
{name:'ReFlux',value:'reflux'},
|
||||
{name:'Alt',value:'alt'}
|
||||
],
|
||||
default : false
|
||||
}, function(props) {
|
||||
this.env.options.architecture = props.architecture;
|
||||
this.config.set('architecture', props.architecture);
|
||||
done();
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
ReactWebpackGenerator.prototype.askForStylesLanguage = function () {
|
||||
var done = this.async();
|
||||
this.prompt({
|
||||
type : 'list',
|
||||
name : 'stylesLanguage',
|
||||
message : 'Which styles language you want to use?',
|
||||
choices: [
|
||||
{name: 'CSS', value: 'css'},
|
||||
{name: 'SASS', value: 'sass'},
|
||||
{name: 'SCSS', value: 'scss'},
|
||||
{name: 'LESS', value: 'less'},
|
||||
{name: 'Stylus', value: 'stylus'}
|
||||
],
|
||||
default : 'css'
|
||||
}, function (props) {
|
||||
this.env.options.stylesLanguage = props.stylesLanguage;
|
||||
this.config.set('styles-language', props.stylesLanguage);
|
||||
done();
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
// Allow to set the generated files suffix for the project when using components
|
||||
// @see https://github.com/newtriks/generator-react-webpack/issues/99
|
||||
ReactWebpackGenerator.prototype.askForComponentSuffix = function() {
|
||||
var done = this.async();
|
||||
this.prompt({
|
||||
type: 'list',
|
||||
name: 'componentSuffix',
|
||||
message: 'Which file suffix do you want to use for components?',
|
||||
choices: [
|
||||
{ name: '.js (default)', value: 'js' },
|
||||
{ name: '.jsx (deprecated)', value: 'jsx' }
|
||||
],
|
||||
default: 'js'
|
||||
}, function (props) {
|
||||
this.env.options.componentSuffix = props.componentSuffix;
|
||||
this.config.set('component-suffix', props.componentSuffix);
|
||||
done();
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
ReactWebpackGenerator.prototype.readIndex = function readIndex() {
|
||||
this.indexFile = this.engine(this.read('../../templates/common/index.html'), this);
|
||||
};
|
||||
|
||||
ReactWebpackGenerator.prototype.createIndexHtml = function createIndexHtml() {
|
||||
this.indexFile = this.indexFile.replace(/'/g, "'");
|
||||
this.write(path.join(this.appPath, 'index.html'), this.indexFile);
|
||||
};
|
||||
|
||||
ReactWebpackGenerator.prototype.packageFiles = function () {
|
||||
this.es6 = this.options.es6;
|
||||
this.reactRouter = this.env.options.reactRouter;
|
||||
this.architecture = this.env.options.architecture;
|
||||
this.stylesLanguage = this.env.options.stylesLanguage;
|
||||
this.template('../../templates/common/_package.json', 'package.json');
|
||||
this.template('../../templates/common/_webpack.config.js', 'webpack.config.js');
|
||||
this.template('../../templates/common/_webpack.dist.config.js', 'webpack.dist.config.js');
|
||||
this.copy('../../templates/common/Gruntfile.js', 'Gruntfile.js');
|
||||
this.copy('../../templates/common/gitignore', '.gitignore');
|
||||
};
|
||||
|
||||
ReactWebpackGenerator.prototype.styleFiles = function styleFiles() {
|
||||
var mainFile = 'main.css';
|
||||
this.copy('styles/' + mainFile, 'src/styles/' + mainFile);
|
||||
};
|
||||
|
||||
ReactWebpackGenerator.prototype.imageFiles = function () {
|
||||
this.sourceRoot(path.join(__dirname, 'templates'));
|
||||
this.directory('images', 'src/images', true);
|
||||
};
|
||||
|
||||
ReactWebpackGenerator.prototype.karmaFiles = function () {
|
||||
this.copy('../../templates/common/karma.conf.js', 'karma.conf.js');
|
||||
};
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
@@ -1,41 +0,0 @@
|
||||
/* Stiziles */
|
||||
|
||||
html, body {
|
||||
background: #222222;
|
||||
}
|
||||
|
||||
/* main */
|
||||
|
||||
.main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #222222;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.main img {
|
||||
width: 103px;
|
||||
height: 89px;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* transitions */
|
||||
|
||||
.fade-enter {
|
||||
opacity: 0.01;
|
||||
transition: opacity .5s ease-in;
|
||||
}
|
||||
|
||||
.fade-enter.fade-enter-active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.fade-leave {
|
||||
opacity: 1;
|
||||
transition: opacity .5s ease-in;
|
||||
}
|
||||
|
||||
.fade-leave.fade-leave-active {
|
||||
opacity: 0.01;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require('../component');
|
||||
@@ -1,17 +0,0 @@
|
||||
'use strict';
|
||||
var path = require('path');
|
||||
var util = require('util');
|
||||
var yeoman = require('yeoman-generator');
|
||||
|
||||
var CommonGenerator = module.exports = function CommonGenerator(args, options, config) {
|
||||
yeoman.generators.NamedBase.apply(this, arguments);
|
||||
};
|
||||
|
||||
util.inherits(CommonGenerator, yeoman.generators.NamedBase);
|
||||
|
||||
CommonGenerator.prototype.setupEnv = function setupEnv() {
|
||||
// Copies the contents of the generator `templates`
|
||||
// directory into your users new application path
|
||||
this.sourceRoot(path.join(__dirname, '../templates/common'));
|
||||
this.directory('root', '.', true);
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
'use strict';
|
||||
var util = require('util');
|
||||
var ScriptBase = require('../script-base.js');
|
||||
|
||||
var ComponentGenerator = module.exports = function ComponentGenerator(args, options, config) {
|
||||
ScriptBase.apply(this, arguments);
|
||||
};
|
||||
|
||||
util.inherits(ComponentGenerator, ScriptBase);
|
||||
|
||||
ComponentGenerator.prototype.createComponentFile = function createComponentFile() {
|
||||
this.option('es6');
|
||||
this.option('rich');
|
||||
|
||||
this.es6 = this.options.es6;
|
||||
this.rich = this.options.rich;
|
||||
|
||||
this.generateComponentTestAndStyle(
|
||||
'Component',
|
||||
'spec/Component',
|
||||
'styles/Component',
|
||||
'components',
|
||||
true
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,148 @@
|
||||
'use strict';
|
||||
let generator = require('yeoman-generator');
|
||||
let utils = require('../../utils/all');
|
||||
let prompts = require('./prompts');
|
||||
let path = require('path');
|
||||
let fs = require('fs');
|
||||
|
||||
// Set the base root directory for our files
|
||||
let baseRootPath = path.dirname(require.resolve('react-webpack-template'));
|
||||
|
||||
module.exports = generator.Base.extend({
|
||||
|
||||
constructor: function() {
|
||||
generator.Base.apply(this, arguments);
|
||||
|
||||
// Make options available
|
||||
this.option('skip-welcome-message', {
|
||||
desc: 'Skip the welcome message',
|
||||
type: Boolean,
|
||||
defaults: false
|
||||
});
|
||||
this.option('skip-install');
|
||||
|
||||
// Use our plain template as source
|
||||
this.sourceRoot(baseRootPath);
|
||||
|
||||
this.config.save();
|
||||
},
|
||||
|
||||
initializing: function() {
|
||||
if(!this.options['skip-welcome-message']) {
|
||||
this.log(require('yeoman-welcome'));
|
||||
this.log('Out of the box I include Webpack and some default React components.\n');
|
||||
}
|
||||
},
|
||||
|
||||
prompting: function() {
|
||||
let done = this.async();
|
||||
this.prompt(prompts, function(props) {
|
||||
|
||||
// Make sure to get the correct app name if it is not the default
|
||||
if(props.appName !== utils.yeoman.getAppName()) {
|
||||
props.appName = utils.yeoman.getAppName(props.appName);
|
||||
}
|
||||
|
||||
// Set needed global vars for yo
|
||||
this.appName = props.appName;
|
||||
this.style = props.style;
|
||||
this.postcss = props.postcss
|
||||
|
||||
// Set needed keys into config
|
||||
this.config.set('appName', this.appName);
|
||||
this.config.set('appPath', this.appPath);
|
||||
this.config.set('style', this.style);
|
||||
this.config.set('postcss', this.postcss);
|
||||
|
||||
this.config.save();
|
||||
|
||||
done();
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
configuring: function() {
|
||||
|
||||
// Generate our package.json. Make sure to also include the required dependencies for styles
|
||||
let defaultSettings = this.fs.readJSON(path.join(baseRootPath, 'package.json'));
|
||||
let packageSettings = {
|
||||
name: this.appName,
|
||||
private: true,
|
||||
version: '0.0.1',
|
||||
description: 'YOUR DESCRIPTION - Generated by generator-react-webpack',
|
||||
main: '',
|
||||
scripts: defaultSettings.scripts,
|
||||
repository: '',
|
||||
keywords: [],
|
||||
author: 'Your name here',
|
||||
devDependencies: defaultSettings.devDependencies,
|
||||
dependencies: defaultSettings.dependencies
|
||||
};
|
||||
|
||||
// Add needed loaders if we have special styles
|
||||
let styleConfig = utils.config.getChoiceByKey('style', this.style);
|
||||
if(styleConfig && styleConfig.packages) {
|
||||
|
||||
for(let dependency of styleConfig.packages) {
|
||||
packageSettings.devDependencies[dependency.name] = dependency.version;
|
||||
}
|
||||
}
|
||||
|
||||
// Add postcss module if enabled
|
||||
let postcssConfig = utils.config.getChoiceByKey('postcss', 'postcss');
|
||||
if(this.postcss && postcssConfig && postcssConfig.packages) {
|
||||
|
||||
for(let dependency of postcssConfig.packages) {
|
||||
packageSettings.devDependencies[dependency.name] = dependency.version;
|
||||
}
|
||||
}
|
||||
|
||||
this.fs.writeJSON(this.destinationPath('package.json'), packageSettings);
|
||||
},
|
||||
|
||||
writing: function() {
|
||||
|
||||
let excludeList = [
|
||||
'LICENSE',
|
||||
'README.md',
|
||||
'CHANGELOG.md',
|
||||
'node_modules',
|
||||
'package.json',
|
||||
'.travis.yml'
|
||||
];
|
||||
|
||||
// Get all files in our repo and copy the ones we should
|
||||
fs.readdir(this.sourceRoot(), (err, items) => {
|
||||
|
||||
for(let item of items) {
|
||||
|
||||
// Skip the item if it is in our exclude list
|
||||
if(excludeList.indexOf(item) !== -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Copy all items to our root
|
||||
let fullPath = path.join(baseRootPath, item);
|
||||
if(fs.lstatSync(fullPath).isDirectory()) {
|
||||
this.bulkDirectory(item, item);
|
||||
} else {
|
||||
if (item === '.npmignore') {
|
||||
this.copy(item, '.gitignore');
|
||||
} else {
|
||||
this.copy(item, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
install: function() {
|
||||
if(this.postcss) {
|
||||
let postcss = require('./postcss');
|
||||
postcss.write(path.join(this.destinationRoot(), 'cfg/base.js'));
|
||||
}
|
||||
|
||||
if(!this.options['skip-install']) {
|
||||
this.installDependencies({ bower: false });
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
'use strict';
|
||||
let fs = require('fs');
|
||||
let esprima = require('esprima');
|
||||
let walk = require('esprima-walk');
|
||||
let escodegen = require('escodegen');
|
||||
|
||||
module.exports = {
|
||||
write: function(path) {
|
||||
let baseConfigPath = path;
|
||||
let cssDialects = ['/\\.css$/', '/\\.sass/', '/\\.scss/', '/\\.less/', '/\\.styl/'];
|
||||
|
||||
let postcss = 'var postcss = { postcss: function() { return []; } }';
|
||||
postcss = esprima.parse(postcss);
|
||||
postcss = postcss.body[0].declarations[0].init.properties[0];
|
||||
|
||||
let data = fs.readFileSync(baseConfigPath, 'utf8');
|
||||
let parsed = esprima.parse(data);
|
||||
|
||||
walk.walkAddParent(parsed, function(node) {
|
||||
if(node.type === 'AssignmentExpression' && node.left.object.name === 'module') {
|
||||
node.right.properties.push(postcss);
|
||||
}
|
||||
|
||||
if(node.type === 'Property' && node.key.name === 'test') {
|
||||
if(cssDialects.indexOf(node.value.raw) > -1) {
|
||||
let current = node.parent.properties[1].value.value;
|
||||
let position = current.split('!', 2).join('!').length;
|
||||
current = [current.slice(0, position), '!postcss-loader', current.slice(position)].join('');
|
||||
|
||||
node.parent.properties[1].value.value = current;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let options = { format: { indent: { style: ' ' } } };
|
||||
let code = escodegen.generate(parsed, options);
|
||||
fs.writeFileSync(baseConfigPath, code, 'utf8');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
let utils = require('../../utils/all');
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
type: 'input',
|
||||
name: 'appName',
|
||||
message: 'Please choose your application name',
|
||||
default: utils.yeoman.getAppName()
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
name: 'style',
|
||||
message: 'Which styles language you want to use?',
|
||||
choices: utils.config.getChoices('style'),
|
||||
default: utils.config.getDefaultChoice('style')
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'postcss',
|
||||
message: 'Enable postcss?',
|
||||
default: false
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,42 @@
|
||||
'use strict';
|
||||
let generator = require('yeoman-generator');
|
||||
let utils = require('../../utils/all');
|
||||
|
||||
module.exports = generator.Base.extend({
|
||||
|
||||
constructor: function() {
|
||||
generator.Base.apply(this, arguments);
|
||||
this.argument('name', { type: String, required: true });
|
||||
this.option('stateless', {
|
||||
desc: 'Create a stateless component instead of a full one',
|
||||
defaults: false
|
||||
});
|
||||
},
|
||||
|
||||
writing: function() {
|
||||
|
||||
let settings = utils.yeoman.getAllSettingsFromComponentName(this.name, this.config.get('style'));
|
||||
let componentType = this.options.stateless ? 'Stateless' : 'Base';
|
||||
|
||||
// Create the style template
|
||||
this.fs.copyTpl(
|
||||
this.templatePath(`styles/Component${settings.style.suffix}`),
|
||||
this.destinationPath(settings.style.path + settings.style.fileName),
|
||||
settings
|
||||
);
|
||||
|
||||
// Create the component
|
||||
this.fs.copyTpl(
|
||||
this.templatePath(`components/${componentType}.js`),
|
||||
this.destinationPath(settings.component.path + settings.component.fileName),
|
||||
settings
|
||||
);
|
||||
|
||||
// Create the unit test
|
||||
this.fs.copyTpl(
|
||||
this.templatePath('tests/Base.js'),
|
||||
this.destinationPath(settings.test.path + settings.test.fileName),
|
||||
settings
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
require('<%= style.webpackPath %>');
|
||||
|
||||
class <%= component.className %> extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="<%= style.className %>">
|
||||
Please edit <%= component.path %>/<%= component.fileName %> to update this component!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
<%= component.className %>.displayName = '<%= component.displayName %>';
|
||||
|
||||
// Uncomment properties you need
|
||||
// <%= component.className %>.propTypes = {};
|
||||
// <%= component.className %>.defaultProps = {};
|
||||
|
||||
export default <%= component.className %>;
|
||||
@@ -0,0 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
require('<%= style.webpackPath %>');
|
||||
|
||||
let <%= component.className %> = (props) => (
|
||||
<div className="<%= style.className %>">
|
||||
Please edit <%= component.path %>/<%= component.fileName %> to update this component!
|
||||
</div>
|
||||
);
|
||||
|
||||
<%= component.className %>.displayName = '<%= component.displayName %>';
|
||||
|
||||
// Uncomment properties you need
|
||||
// <%= component.className %>.propTypes = {};
|
||||
// <%= component.className %>.defaultProps = {};
|
||||
|
||||
export default <%= component.className %>;
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
.<%= classedName %> {
|
||||
.<%= style.className %> {
|
||||
border: 1px dashed #f00;
|
||||
}
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
.<%= classedName %> {
|
||||
.<%= style.className %> {
|
||||
border: 1px dashed #f00;
|
||||
}
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
.<%= classedName %>
|
||||
.<%= style.className %>
|
||||
border: 1px dashed #f00
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
.<%= classedName %> {
|
||||
.<%= style.className %> {
|
||||
border: 1px dashed #f00;
|
||||
}
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
.<%= classedName %>
|
||||
.<%= style.className %>
|
||||
border 1px dashed #f00
|
||||
@@ -0,0 +1,22 @@
|
||||
/*eslint-env node, mocha */
|
||||
/*global expect */
|
||||
/*eslint no-console: 0*/
|
||||
'use strict';
|
||||
|
||||
// Uncomment the following lines to use the react test utilities
|
||||
// import TestUtils from 'react-addons-test-utils';
|
||||
import createComponent from 'helpers/shallowRenderHelper';
|
||||
|
||||
import <%= component.className %> from '<%= component.webpackPath %>';
|
||||
|
||||
describe('<%= component.className %>', () => {
|
||||
let component;
|
||||
|
||||
beforeEach(() => {
|
||||
component = createComponent(<%= component.className %>);
|
||||
});
|
||||
|
||||
it('should have its component name as default className', () => {
|
||||
expect(component.props.className).to.equal('<%= style.className %>');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
//Support for Visual Studio Code https://code.visualstudio.com/docs/languages/javascript
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var ScriptBase = require('../script-base.js');
|
||||
|
||||
var MainGenerator = module.exports = function MainGenerator(args, options, config) {
|
||||
ScriptBase.apply(this, arguments);
|
||||
};
|
||||
|
||||
util.inherits(MainGenerator, ScriptBase);
|
||||
|
||||
MainGenerator.prototype.createAppFile = function createAppFile(scriptAppName) {
|
||||
this.reactRouter = this.env.options.reactRouter;
|
||||
this.scriptAppName = scriptAppName;
|
||||
this.appTemplate('App', 'components/' + scriptAppName);
|
||||
this.testTemplate('spec/App', 'components/' + scriptAppName);
|
||||
};
|
||||
|
||||
MainGenerator.prototype.createMainFile = function createMainFile() {
|
||||
if(this.env.options.reactRouter) {
|
||||
this.appTemplate('main', 'components/main');
|
||||
}
|
||||
};
|
||||
|
||||
MainGenerator.prototype.createDispatcher = function createDispatcher() {
|
||||
if(this.env.options.architecture=='flux') {
|
||||
this.appTemplate('Dispatcher', 'dispatcher/' + this.scriptAppName + 'Dispatcher');
|
||||
}
|
||||
};
|
||||
|
||||
MainGenerator.prototype.createAltjsFile = function createAltjsFile() {
|
||||
if(this.env.options.architecture=='alt') {
|
||||
this.appTemplate('alt', 'alt');
|
||||
}
|
||||
};
|
||||
+29
-18
@@ -1,14 +1,16 @@
|
||||
{
|
||||
"name": "generator-react-webpack",
|
||||
"version": "1.2.13",
|
||||
"description": "Yeoman generator for ReactJS and Webpack",
|
||||
"version": "3.2.0",
|
||||
"description": "Yeoman generator for using React with Webpack via Babel",
|
||||
"keywords": [
|
||||
"yeoman-generator",
|
||||
"react",
|
||||
"reactjs",
|
||||
"webpack",
|
||||
"scaffold",
|
||||
"framework",
|
||||
"component",
|
||||
"frontend",
|
||||
"front-end",
|
||||
"app"
|
||||
],
|
||||
@@ -19,33 +21,42 @@
|
||||
"email": "simon@newtriks.com",
|
||||
"url": "https://github.com/newtriks"
|
||||
},
|
||||
"main": "app/index.js",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Christian Schilling",
|
||||
"email": "cs@weblogixx.de",
|
||||
"url": "https://github.com/weblogixx"
|
||||
}
|
||||
],
|
||||
"main": "generators/app/index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/newtriks/generator-react-webpack.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha"
|
||||
"test": "mocha",
|
||||
"release:major": "npm version major && npm publish && git push --follow-tags",
|
||||
"release:minor": "npm version minor && npm publish && git push --follow-tags",
|
||||
"release:patch": "npm version patch && npm publish && git push --follow-tags"
|
||||
},
|
||||
"dependencies": {
|
||||
"yeoman-generator": "^0.17.6"
|
||||
"react-webpack-template": "^1.0.0",
|
||||
"underscore.string": "^3.2.2",
|
||||
"yeoman-generator": "^0.22.0",
|
||||
"yeoman-welcome": "^1.0.1",
|
||||
"esprima": "^2.7.0",
|
||||
"esprima-walk": "^0.1.0",
|
||||
"escodegen": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "^1.21.4",
|
||||
"underscore.string": "^2.3.3",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-cli": "^0.1.13"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"yo": ">=1.2.0"
|
||||
"chai": "^3.2.0",
|
||||
"mocha": "^2.3.2",
|
||||
"yeoman-assert": "^2.1.1",
|
||||
"yeoman-test": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0",
|
||||
"node": ">=4.0.0",
|
||||
"iojs": ">=1.1.0"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT"
|
||||
}
|
||||
]
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
module.exports = require('../store');
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
'use strict';
|
||||
var util = require('util');
|
||||
var path = require('path');
|
||||
var yeoman = require('yeoman-generator');
|
||||
var generalUtils = require('./util.js');
|
||||
|
||||
var Generator = module.exports = function Generator() {
|
||||
yeoman.generators.NamedBase.apply(this, arguments);
|
||||
|
||||
// Add capitalize mixin
|
||||
this._.mixin({ 'capitalize': generalUtils.capitalize });
|
||||
this._.mixin({ 'capitalizeFile': generalUtils.capitalizeFile });
|
||||
this._.mixin({ 'capitalizeClass': generalUtils.capitalizeClass });
|
||||
this._.mixin({ 'lowercase': generalUtils.lowercase });
|
||||
|
||||
this.appname = path.basename(process.cwd());
|
||||
|
||||
this.appname = this._.slugify(this._.humanize(this.appname));
|
||||
this.scriptAppName = this._.camelize(this._.capitalize(this.appname)) + generalUtils.appName(this);
|
||||
this.classedFileName = this._.capitalizeFile(this.name);
|
||||
this.classedName = this._.capitalizeClass(this.name);
|
||||
this.stylesLanguage = this.config.get('styles-language');
|
||||
this.architecture = this.config.get('architecture');
|
||||
|
||||
if (typeof this.options.appPath === 'undefined') {
|
||||
this.options.appPath = this.options.appPath || 'src';
|
||||
}
|
||||
|
||||
if (typeof this.options.testPath === 'undefined') {
|
||||
this.options.testPath = this.options.testPath || 'test/spec';
|
||||
}
|
||||
|
||||
if (typeof this.options.stylesPath === 'undefined') {
|
||||
this.options.stylesPath = this.options.stylesPath || 'src/styles';
|
||||
}
|
||||
|
||||
var sourceRoot = '/templates/';
|
||||
this.scriptSuffix = '.js';
|
||||
this.reactSuffix = '.js';
|
||||
|
||||
// Add support for generated file legacy fallback
|
||||
// @see https://github.com/newtriks/generator-react-webpack/issues/99
|
||||
this.reactComponentSuffix = this.config.get('component-suffix');
|
||||
switch(this.reactComponentSuffix) {
|
||||
case 'jsx':
|
||||
this.reactComponentSuffix = '.jsx';
|
||||
break;
|
||||
default:
|
||||
this.reactComponentSuffix = '.js';
|
||||
}
|
||||
|
||||
this.stylesSuffix = '.css';
|
||||
|
||||
switch(this.stylesLanguage) {
|
||||
case 'sass':
|
||||
this.stylesSuffix = '.sass';
|
||||
break;
|
||||
case 'scss':
|
||||
this.stylesSuffix = '.scss';
|
||||
break;
|
||||
case 'less':
|
||||
this.stylesSuffix = '.less';
|
||||
break;
|
||||
case 'stylus':
|
||||
this.stylesSuffix = '.styl';
|
||||
break;
|
||||
}
|
||||
|
||||
this.sourceRoot(path.join(__dirname, sourceRoot));
|
||||
};
|
||||
|
||||
util.inherits(Generator, yeoman.generators.NamedBase);
|
||||
|
||||
Generator.prototype.appTemplate = function (src, dest) {
|
||||
yeoman.generators.Base.prototype.template.apply(this, [
|
||||
path.join('javascript', src + this.scriptSuffix),
|
||||
path.join(this.options.appPath, dest) + this.scriptSuffix
|
||||
]);
|
||||
};
|
||||
|
||||
Generator.prototype.reactComponentTemplate = function (src, dest) {
|
||||
yeoman.generators.Base.prototype.template.apply(this, [
|
||||
path.join('javascript', src + this.reactSuffix),
|
||||
path.join(this.options.appPath, dest) + this.reactComponentSuffix
|
||||
]);
|
||||
};
|
||||
|
||||
Generator.prototype.testTemplate = function (src, dest) {
|
||||
yeoman.generators.Base.prototype.template.apply(this, [
|
||||
src + this.scriptSuffix,
|
||||
path.join(this.options.testPath, dest) + this.scriptSuffix
|
||||
]);
|
||||
};
|
||||
|
||||
Generator.prototype.stylesTemplate = function (src, dest) {
|
||||
yeoman.generators.Base.prototype.template.apply(this, [
|
||||
src + this.stylesSuffix,
|
||||
path.join(this.options.stylesPath, dest) + this.stylesSuffix
|
||||
]);
|
||||
};
|
||||
|
||||
Generator.prototype.htmlTemplate = function (src, dest) {
|
||||
yeoman.generators.Base.prototype.template.apply(this, [
|
||||
src,
|
||||
path.join(this.options.appPath, dest.toLowerCase())
|
||||
]);
|
||||
};
|
||||
|
||||
Generator.prototype.generateSourceAndTest = function (appTemplate, testTemplate, targetDirectory) {
|
||||
this.appTemplate(appTemplate, path.join(targetDirectory, this._.capitalizeFile(this.name)));
|
||||
this.testTemplate(testTemplate, path.join(targetDirectory, this._.capitalizeFile(this.name)));
|
||||
};
|
||||
|
||||
Generator.prototype.generateComponentTestAndStyle = function (componentTemplate, testTemplate, stylesTemplate, targetDirectory) {
|
||||
this.reactComponentTemplate(componentTemplate, path.join(targetDirectory, this._.capitalizeFile(this.name)));
|
||||
this.testTemplate(testTemplate, path.join(targetDirectory, this._.capitalizeFile(this.name)));
|
||||
this.stylesTemplate(stylesTemplate, path.join(this._.capitalizeFile(this.name)));
|
||||
};
|
||||
@@ -1,42 +0,0 @@
|
||||
'use strict';
|
||||
var util = require('util');
|
||||
var ScriptBase = require('../script-base.js');
|
||||
|
||||
var StoreGenerator = module.exports = function StoreGenerator(args, options, config) {
|
||||
if (!args[0]) console.log('\n Please specify a name for this store \n');
|
||||
else {
|
||||
args[0] += 'Store';
|
||||
ScriptBase.apply(this, arguments)
|
||||
}
|
||||
};
|
||||
|
||||
util.inherits(StoreGenerator, ScriptBase);
|
||||
|
||||
StoreGenerator .prototype.createStoreFile = function createStoreFile() {
|
||||
this.option('es6');
|
||||
|
||||
this.es6 = this.options.es6;
|
||||
|
||||
var storeTemplate;
|
||||
switch (this.architecture){
|
||||
case 'flux':
|
||||
storeTemplate = 'FluxStore';
|
||||
this.dispatcherName = this._.capitalizeFile(this.config.get('app-name')) + 'AppDispatcher';
|
||||
break;
|
||||
case 'reflux':
|
||||
storeTemplate = 'RefluxStore';
|
||||
break;
|
||||
case 'alt':
|
||||
storeTemplate = 'AltStore';
|
||||
break;
|
||||
}
|
||||
|
||||
console.log('Creating ' + this.architecture + ' store');
|
||||
|
||||
|
||||
this.generateSourceAndTest(
|
||||
storeTemplate,
|
||||
'spec/Store',
|
||||
'stores'
|
||||
);
|
||||
};
|
||||
@@ -1,125 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var mountFolder = function (connect, dir) {
|
||||
return connect.static(require('path').resolve(dir));
|
||||
};
|
||||
|
||||
var webpackDistConfig = require('./webpack.dist.config.js'),
|
||||
webpackDevConfig = require('./webpack.config.js');
|
||||
|
||||
module.exports = function (grunt) {
|
||||
// Let *load-grunt-tasks* require everything
|
||||
require('load-grunt-tasks')(grunt);
|
||||
|
||||
// Read configuration from package.json
|
||||
var pkgConfig = grunt.file.readJSON('package.json');
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: pkgConfig,
|
||||
|
||||
webpack: {
|
||||
options: webpackDistConfig,
|
||||
dist: {
|
||||
cache: false
|
||||
}
|
||||
},
|
||||
|
||||
'webpack-dev-server': {
|
||||
options: {
|
||||
hot: true,
|
||||
port: 8000,
|
||||
webpack: webpackDevConfig,
|
||||
publicPath: '/assets/',
|
||||
contentBase: './<%= pkg.src %>/'
|
||||
},
|
||||
|
||||
start: {
|
||||
keepAlive: true
|
||||
}
|
||||
},
|
||||
|
||||
connect: {
|
||||
options: {
|
||||
port: 8000
|
||||
},
|
||||
|
||||
dist: {
|
||||
options: {
|
||||
keepalive: true,
|
||||
middleware: function (connect) {
|
||||
return [
|
||||
mountFolder(connect, pkgConfig.dist)
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
open: {
|
||||
options: {
|
||||
delay: 500
|
||||
},
|
||||
dev: {
|
||||
path: 'http://localhost:<%= connect.options.port %>/webpack-dev-server/'
|
||||
},
|
||||
dist: {
|
||||
path: 'http://localhost:<%= connect.options.port %>/'
|
||||
}
|
||||
},
|
||||
|
||||
karma: {
|
||||
unit: {
|
||||
configFile: 'karma.conf.js'
|
||||
}
|
||||
},
|
||||
|
||||
copy: {
|
||||
dist: {
|
||||
files: [
|
||||
// includes files within path
|
||||
{
|
||||
flatten: true,
|
||||
expand: true,
|
||||
src: ['<%= pkg.src %>/*'],
|
||||
dest: '<%= pkg.dist %>/',
|
||||
filter: 'isFile'
|
||||
},
|
||||
{
|
||||
flatten: true,
|
||||
expand: true,
|
||||
src: ['<%= pkg.src %>/images/*'],
|
||||
dest: '<%= pkg.dist %>/images/'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
clean: {
|
||||
dist: {
|
||||
files: [{
|
||||
dot: true,
|
||||
src: [
|
||||
'<%= pkg.dist %>'
|
||||
]
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
grunt.registerTask('serve', function (target) {
|
||||
if (target === 'dist') {
|
||||
return grunt.task.run(['build', 'open:dist', 'connect:dist']);
|
||||
}
|
||||
|
||||
grunt.task.run([
|
||||
'open:dev',
|
||||
'webpack-dev-server'
|
||||
]);
|
||||
});
|
||||
|
||||
grunt.registerTask('test', ['karma']);
|
||||
|
||||
grunt.registerTask('build', ['clean', 'copy', 'webpack']);
|
||||
|
||||
grunt.registerTask('default', []);
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
{
|
||||
"name": "<%= _.slugify(appname) %>",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"repository": "",
|
||||
"private": true,
|
||||
"src": "src",
|
||||
"test": "test",
|
||||
"dist": "dist",
|
||||
"mainInput": "<% if (reactRouter) { %>main<% } else { %><%= scriptAppName %><% } %>",
|
||||
"mainOutput": "main",
|
||||
"dependencies": {<% if (reactRouter) { %>
|
||||
"react-router": "0.13.x",<% } if (architecture === 'flux') { %>
|
||||
"flux": "^2.0.1",
|
||||
"events": "^1.0.2",
|
||||
"object-assign": "^2.0.0", <% } if (architecture === 'reflux') {%>
|
||||
"reflux": "^0.2.7", <% } if (architecture === 'alt') { %>
|
||||
"alt": "^0.16.5", <% } %>
|
||||
"react": "0.13.x",
|
||||
"normalize.css": "~3.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "^5.0.0",
|
||||
"babel-loader": "^5.0.0",
|
||||
"grunt": "~0.4.5",
|
||||
"eslint": "^0.21.2",
|
||||
"eslint-loader": "^0.11.2",
|
||||
"eslint-plugin-react": "^2.4.0",
|
||||
"load-grunt-tasks": "~0.6.0",
|
||||
"grunt-contrib-connect": "~0.8.0",
|
||||
"grunt-webpack": "~1.0.8",
|
||||
"jasmine-core": "^2.3.4",
|
||||
"karma": "~0.13.9",
|
||||
"karma-jasmine": "^0.3.5",
|
||||
"karma-phantomjs-launcher": "~0.2.1",
|
||||
"karma-script-launcher": "~0.1.0",
|
||||
"karma-webpack": "^1.7.0",
|
||||
"style-loader": "~0.8.0",
|
||||
"url-loader": "~0.5.5",
|
||||
"css-loader": "~0.9.0",
|
||||
"grunt-karma": "~0.12.1",
|
||||
"grunt-open": "~0.2.3",
|
||||
"grunt-contrib-copy": "~0.5.0",
|
||||
"grunt-contrib-clean": "~0.6.0",<% if (stylesLanguage.match(/s[ac]ss/)) { %>
|
||||
"sass-loader": "^1.0.1",<% } %><% if (stylesLanguage === 'less') { %>
|
||||
"less-loader": "^2.0.0",<% } %><% if (stylesLanguage === 'stylus') { %>
|
||||
"stylus-loader": "^0.5.0",<% } %>
|
||||
"react-hot-loader": "^1.0.7",
|
||||
"webpack": "~1.10.0",
|
||||
"webpack-dev-server": "~1.10.0"
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Webpack development server configuration
|
||||
*
|
||||
* This file is set up for serving the webpack-dev-server, which will watch for changes and recompile as required if
|
||||
* the subfolder /webpack-dev-server/ is visited. Visiting the root will not automatically reload.
|
||||
*/
|
||||
'use strict';
|
||||
var webpack = require('webpack');
|
||||
|
||||
module.exports = {
|
||||
|
||||
output: {
|
||||
filename: 'main.js',
|
||||
publicPath: '/assets/'
|
||||
},
|
||||
|
||||
cache: true,
|
||||
debug: true,
|
||||
devtool: 'sourcemap',
|
||||
entry: [
|
||||
'webpack/hot/only-dev-server',
|
||||
'./src/components/<% if (reactRouter) { %>main<% } else { %><%= scriptAppName %><% } %>.js'
|
||||
],
|
||||
|
||||
stats: {
|
||||
colors: true,
|
||||
reasons: true
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: ['', '.js', '.jsx'],
|
||||
alias: {
|
||||
'styles': __dirname + '/src/styles',
|
||||
'mixins': __dirname + '/src/mixins',
|
||||
'components': __dirname + '/src/components/'<% if(architecture==='flux'||architecture=='reflux') { %>,
|
||||
'stores': __dirname + '/src/stores/',
|
||||
'actions': __dirname + '/src/actions/'<% } %>
|
||||
}
|
||||
},
|
||||
module: {
|
||||
preLoaders: [{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'eslint-loader'
|
||||
}],
|
||||
loaders: [{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'react-hot!babel-loader'
|
||||
},<% if (stylesLanguage === 'sass') { %> {
|
||||
test: /\.sass/,
|
||||
loader: 'style-loader!css-loader!sass-loader?outputStyle=expanded&indentedSyntax'
|
||||
},<% } %><% if (stylesLanguage === 'scss') { %> {
|
||||
test: /\.scss/,
|
||||
loader: 'style-loader!css-loader!sass-loader?outputStyle=expanded'
|
||||
},<% } %><% if (stylesLanguage === 'less') { %> {
|
||||
test: /\.less/,
|
||||
loader: 'style-loader!css-loader!less-loader'
|
||||
},<% } %><% if (stylesLanguage === 'stylus') { %> {
|
||||
test: /\.styl/,
|
||||
loader: 'style-loader!css-loader!stylus-loader'
|
||||
},<% } %> {
|
||||
test: /\.css$/,
|
||||
loader: 'style-loader!css-loader'
|
||||
}, {
|
||||
test: /\.(png|jpg|woff|woff2)$/,
|
||||
loader: 'url-loader?limit=8192'
|
||||
}]
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new webpack.HotModuleReplacementPlugin()
|
||||
]
|
||||
|
||||
};
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Webpack distribution configuration
|
||||
*
|
||||
* This file is set up for serving the distribution version. It will be compiled to dist/ by default
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var webpack = require('webpack');
|
||||
|
||||
module.exports = {
|
||||
|
||||
output: {
|
||||
publicPath: '/assets/',
|
||||
path: 'dist/assets/',
|
||||
filename: 'main.js'
|
||||
},
|
||||
|
||||
debug: false,
|
||||
devtool: false,
|
||||
entry: './src/components/<% if (reactRouter) { %>main<% } else { %><%= scriptAppName %><% } %>.js',
|
||||
|
||||
stats: {
|
||||
colors: true,
|
||||
reasons: false
|
||||
},
|
||||
|
||||
plugins: [
|
||||
new webpack.optimize.DedupePlugin(),
|
||||
new webpack.optimize.UglifyJsPlugin(),
|
||||
new webpack.optimize.OccurenceOrderPlugin(),
|
||||
new webpack.optimize.AggressiveMergingPlugin(),
|
||||
new webpack.NoErrorsPlugin()
|
||||
],
|
||||
|
||||
resolve: {
|
||||
extensions: ['', '.js', '.jsx'],
|
||||
alias: {
|
||||
'styles': __dirname + '/src/styles',
|
||||
'mixins': __dirname + '/src/mixins',
|
||||
'components': __dirname + '/src/components/'<% if(architecture==='flux'||architecture=='reflux') { %>,
|
||||
'stores': __dirname + '/src/stores/',
|
||||
'actions': __dirname + '/src/actions/'<% } %>
|
||||
}
|
||||
},
|
||||
|
||||
module: {
|
||||
preLoaders: [{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'eslint-loader'
|
||||
}],
|
||||
loaders: [{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader'
|
||||
}, {
|
||||
test: /\.css$/,
|
||||
loader: 'style-loader!css-loader'
|
||||
},<% if (stylesLanguage === 'sass') { %> {
|
||||
test: /\.sass/,
|
||||
loader: 'style-loader!css-loader!sass-loader?outputStyle=expanded&indentedSyntax'
|
||||
},<% } %><% if (stylesLanguage === 'scss') { %> {
|
||||
test: /\.scss/,
|
||||
loader: 'style-loader!css-loader!sass-loader?outputStyle=expanded'
|
||||
},<% } %><% if (stylesLanguage === 'less') { %> {
|
||||
test: /\.less/,
|
||||
loader: 'style-loader!css-loader!less-loader'
|
||||
},<% } %><% if (stylesLanguage === 'stylus') { %> {
|
||||
test: /\.styl/,
|
||||
loader: 'style-loader!css-loader!stylus-loader'
|
||||
},<% } %> {
|
||||
test: /\.(png|jpg|woff|woff2)$/,
|
||||
loader: 'url-loader?limit=8192'
|
||||
}]
|
||||
}
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
### SublimeText ###
|
||||
*.sublime-workspace
|
||||
|
||||
### OSX ###
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear on external disk
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
|
||||
### Windows ###
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# App specific
|
||||
|
||||
node_modules/
|
||||
.tmp
|
||||
dist
|
||||
/src/main.js
|
||||
@@ -1,23 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title></title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
<body>
|
||||
<!--[if lt IE 8]>
|
||||
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
|
||||
<![endif]-->
|
||||
<div id="content">
|
||||
<h1>If you can see this, something is broken (or JS is not enabled)!!.</h1>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__
|
||||
</script>
|
||||
<script type="text/javascript" src="assets/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,93 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine'],
|
||||
files: [
|
||||
'test/helpers/pack/**/*.js',
|
||||
'test/helpers/react/**/*.js',
|
||||
'test/spec/components/**/*.js'<% if(architecture === 'flux'||architecture === 'reflux') { %>,
|
||||
'test/spec/stores/**/*.js',
|
||||
'test/spec/actions/**/*.js'<% } %>
|
||||
],
|
||||
preprocessors: {
|
||||
'test/helpers/createComponent.js': ['webpack'],
|
||||
'test/spec/components/**/*.js': ['webpack'],
|
||||
'test/spec/components/**/*.jsx': ['webpack']<% if(architecture === 'flux'||architecture === 'reflux') { %>,
|
||||
'test/spec/stores/**/*.js': ['webpack'],
|
||||
'test/spec/actions/**/*.js': ['webpack']<% } %>
|
||||
},
|
||||
webpack: {
|
||||
cache: true,
|
||||
module: {
|
||||
loaders: [{
|
||||
test: /\.gif/,
|
||||
loader: 'url-loader?limit=10000&mimetype=image/gif'
|
||||
}, {
|
||||
test: /\.jpg/,
|
||||
loader: 'url-loader?limit=10000&mimetype=image/jpg'
|
||||
}, {
|
||||
test: /\.png/,
|
||||
loader: 'url-loader?limit=10000&mimetype=image/png'
|
||||
}, {
|
||||
test: /\.(js|jsx)$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /node_modules/
|
||||
},<% if (stylesLanguage === 'sass') { %> {
|
||||
test: /\.sass/,
|
||||
loader: 'style-loader!css-loader!sass-loader?outputStyle=expanded'
|
||||
},<% } %><% if (stylesLanguage === 'scss') { %> {
|
||||
test: /\.scss/,
|
||||
loader: 'style-loader!css-loader!sass-loader?outputStyle=expanded'
|
||||
},<% } %><% if (stylesLanguage === 'less') { %> {
|
||||
test: /\.less/,
|
||||
loader: 'style-loader!css-loader!less-loader'
|
||||
},<% } %><% if (stylesLanguage === 'stylus') { %> {
|
||||
test: /\.styl/,
|
||||
loader: 'style-loader!css-loader!stylus-loader'
|
||||
},<% } %> {
|
||||
test: /\.css$/,
|
||||
loader: 'style-loader!css-loader'
|
||||
}, {
|
||||
test: /\.woff/,
|
||||
loader: 'url-loader?limit=10000&mimetype=application/font-woff'
|
||||
}, {
|
||||
test: /\.woff2/,
|
||||
loader: 'url-loader?limit=10000&mimetype=application/font-woff2'
|
||||
}]
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'styles': path.join(process.cwd(), './src/styles/'),
|
||||
'components': path.join(process.cwd(), './src/components/')<% if(architecture === 'flux'||architecture === 'reflux') { %>,
|
||||
'stores': '../../../src/stores/',
|
||||
'actions': '../../../src/actions/'<% } %>,
|
||||
'helpers': path.join(process.cwd(), './test/helpers/')
|
||||
}
|
||||
}
|
||||
},
|
||||
webpackMiddleware: {
|
||||
noInfo: true,
|
||||
stats: {
|
||||
colors: true
|
||||
}
|
||||
},
|
||||
exclude: [],
|
||||
port: 8080,
|
||||
logLevel: config.LOG_INFO,
|
||||
colors: true,
|
||||
autoWatch: false,
|
||||
browsers: ['PhantomJS'],
|
||||
reporters: ['dots'],
|
||||
captureTimeout: 60000,
|
||||
singleRun: true,
|
||||
plugins: [
|
||||
require('karma-webpack'),
|
||||
require('karma-jasmine'),
|
||||
require('karma-phantomjs-launcher')
|
||||
]
|
||||
});
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
"modules": true
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"amd": true,
|
||||
"es6": true
|
||||
},
|
||||
"rules": {
|
||||
"quotes": [ 1, "single" ],
|
||||
"no-undef": false,
|
||||
"global-strict": false,
|
||||
"no-extra-semi": 1,
|
||||
"no-underscore-dangle": false
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"esnext": true,
|
||||
"bitwise": true,
|
||||
"camelcase": false,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"immed": true,
|
||||
"indent": 2,
|
||||
"latedef": true,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"quotmark": "false",
|
||||
"regexp": true,
|
||||
"undef": true,
|
||||
"unused": false,
|
||||
"strict": true,
|
||||
"trailing": true,
|
||||
"smarttabs": true,
|
||||
"white": true,
|
||||
"newcap": false,
|
||||
"globals": {
|
||||
"React": true
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"esnext": true,
|
||||
"bitwise": true,
|
||||
"camelcase": false,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"immed": true,
|
||||
"indent": 2,
|
||||
"latedef": true,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"quotmark": "false",
|
||||
"regexp": true,
|
||||
"undef": true,
|
||||
"unused": false,
|
||||
"strict": true,
|
||||
"trailing": true,
|
||||
"smarttabs": true,
|
||||
"white": true,
|
||||
"newcap": false,
|
||||
"globals": {
|
||||
"after": false,
|
||||
"afterEach": false,
|
||||
"react": false,
|
||||
"before": false,
|
||||
"beforeEach": false,
|
||||
"browser": false,
|
||||
"describe": false,
|
||||
"expect": false,
|
||||
"inject": false,
|
||||
"it": false,
|
||||
"spyOn": false,
|
||||
"jasmine": false,
|
||||
"spyOnConstructor": false,
|
||||
"React": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Function to get the shallow output for a given component
|
||||
* As we are using phantom.js, we also need to include the fn.proto.bind shim!
|
||||
*
|
||||
* @see http://simonsmith.io/unit-testing-react-components-without-a-dom/
|
||||
* @author somonsmith
|
||||
*/
|
||||
|
||||
// Add missing methods to phantom.js
|
||||
import './pack/phantomjs-shims';
|
||||
|
||||
import React from 'react/addons';
|
||||
const TestUtils = React.addons.TestUtils;
|
||||
|
||||
/**
|
||||
* Get the shallow rendered component
|
||||
*
|
||||
* @param {Object} component The component to return the output for
|
||||
* @param {Object} props [optional] The components properties
|
||||
* @param {Mixed} ...children [optional] List of children
|
||||
* @return {Object} Shallow rendered output
|
||||
*/
|
||||
export default function createComponent(component, props = {}, ...children) {
|
||||
const shallowRenderer = TestUtils.createRenderer();
|
||||
shallowRenderer.render(React.createElement(component, props, children.length > 1 ? children : children[0]));
|
||||
return shallowRenderer.getRenderOutput();
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
(function() {
|
||||
|
||||
var Ap = Array.prototype;
|
||||
var slice = Ap.slice;
|
||||
var Fp = Function.prototype;
|
||||
|
||||
if (!Fp.bind) {
|
||||
// PhantomJS doesn't support Function.prototype.bind natively, so
|
||||
// polyfill it whenever this module is required.
|
||||
Fp.bind = function(context) {
|
||||
var func = this;
|
||||
var args = slice.call(arguments, 1);
|
||||
|
||||
function bound() {
|
||||
var invokedAsConstructor = func.prototype && (this instanceof func);
|
||||
return func.apply(
|
||||
// Ignore the context parameter when invoking the bound function
|
||||
// as a constructor. Note that this includes not only constructor
|
||||
// invocations using the new keyword but also calls to base class
|
||||
// constructors such as BaseClass.call(this, ...) or super(...).
|
||||
!invokedAsConstructor && context || this,
|
||||
args.concat(slice.call(arguments))
|
||||
);
|
||||
}
|
||||
|
||||
// The bound function must share the .prototype of the unbound
|
||||
// function so that any object created by one constructor will count
|
||||
// as an instance of both constructors.
|
||||
bound.prototype = func.prototype;
|
||||
|
||||
return bound;
|
||||
};
|
||||
}
|
||||
})();
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
||||
var alt = require('../alt');
|
||||
|
||||
<% if (es6) { %>class <%= classedName %> {
|
||||
|
||||
}; <% }
|
||||
else { %>var <%= classedName %> = alt.createActions(function () {
|
||||
|
||||
}); <% } %>
|
||||
|
||||
<% if (es6) { %>export default alt.createActions(<%= classedName %>); <% }
|
||||
else { %>module.exports = <%= classedName %>; <% } %>
|
||||
@@ -1,21 +0,0 @@
|
||||
var alt = require('../alt');
|
||||
|
||||
<% if (es6) { %>class <%= classedName %> {
|
||||
constructor() {
|
||||
|
||||
this.bindListeners({
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
} <% }
|
||||
else { %>var <%= classedName %> = alt.createStore({
|
||||
|
||||
bindListeners: {
|
||||
|
||||
}
|
||||
|
||||
}); <% } %>
|
||||
|
||||
<% if (es6) { %>export default alt.createStore(<%= classedName %>, '<%= classedName %>'); <% }
|
||||
else { %>module.exports = <%= classedName %>; <% } %>
|
||||
@@ -1,26 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react/addons');
|
||||
var ReactTransitionGroup = React.addons.TransitionGroup;
|
||||
|
||||
// CSS
|
||||
require('normalize.css');
|
||||
require('../styles/main.css');
|
||||
|
||||
var imageURL = require('../images/yeoman.png');
|
||||
|
||||
var <%= scriptAppName %> = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div className="main">
|
||||
<ReactTransitionGroup transitionName="fade">
|
||||
<img src={imageURL} />
|
||||
</ReactTransitionGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
<% if (!reactRouter) {
|
||||
%>React.render(<<%= scriptAppName %> />, document.getElementById('content')); // jshint ignore:line
|
||||
<% } %>
|
||||
module.exports = <%= scriptAppName %>;
|
||||
@@ -1,36 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var React = require('react/addons');<% if(rich && architecture === 'reflux'){%>
|
||||
var Reflux = require('Reflux');<%}%>
|
||||
<% if(rich && architecture === 'flux' || architecture === 'reflux'){%>
|
||||
//var Actions = require('actions/xxx')<%}%>
|
||||
|
||||
<% if (stylesLanguage === 'css') { %>require('styles/<%= classedFileName %>.css');<% } %><%
|
||||
if (stylesLanguage === 'sass') { %>require('styles/<%= classedFileName %>.sass');<% } %><%
|
||||
if (stylesLanguage === 'scss') { %>require('styles/<%= classedFileName %>.scss');<% } %><%
|
||||
if (stylesLanguage === 'less') { %>require('styles/<%= classedFileName %>.less');<% } %><%
|
||||
if (stylesLanguage === 'stylus') { %>require('styles/<%= classedFileName %>.styl');<% } %>
|
||||
|
||||
var <%= classedName %> = React.createClass({<% if(rich){%>
|
||||
mixins: [<% if(architecture === 'reflux'){%>Reflux.ListenerMixin<%}%>],
|
||||
getInitialState: function() {
|
||||
return {};
|
||||
},
|
||||
getDefaultProps: function() {},
|
||||
componentWillMount: function() {},
|
||||
componentDidMount: function() {},
|
||||
shouldComponentUpdate: function() {},
|
||||
componentDidUpdate: function() {},
|
||||
componentWillUnmount: function() {},<%}%>
|
||||
|
||||
render: function () {
|
||||
return (
|
||||
<div className="<%= classedName %>">
|
||||
<p>Content for <%= classedName %></p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
<% if (es6) { %>export default <%= classedName %>;<% }
|
||||
else { %>module.exports = <%= classedName %>;<% } %>
|
||||
@@ -1,3 +0,0 @@
|
||||
var Dispatcher = require('flux').Dispatcher;
|
||||
|
||||
module.exports = new Dispatcher();
|
||||
@@ -1,8 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var <%= classedName %> = {
|
||||
|
||||
};
|
||||
|
||||
<% if (es6) { %> export default <%= classedName %>; <% }
|
||||
else { %>module.exports = <%= classedName %>; <% } %>
|
||||
@@ -1,20 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var assign = require('object-assign');
|
||||
var <%= dispatcherName %> = require('../dispatcher/<%= dispatcherName %>');
|
||||
|
||||
var <%= classedName %> = assign({}, EventEmitter.prototype, {
|
||||
|
||||
});
|
||||
|
||||
<%= classedName %>.dispatchToken = <%= dispatcherName %>.register(function(action) {
|
||||
|
||||
switch(action.type) {
|
||||
default:
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
<% if (es6) { %> export default <%= classedName %>; <% }
|
||||
else { %>module.exports = <%= classedName %>; <% } %>
|
||||
@@ -1,11 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var Reflux = require('reflux');
|
||||
|
||||
var <%= classedName %> = Reflux.createActions([
|
||||
|
||||
]);
|
||||
|
||||
|
||||
<% if (es6) { %> export default <%= classedName %>; <% }
|
||||
else { %>module.exports = <%= classedName %>; <% } %>
|
||||
@@ -1,14 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var Reflux = require('reflux');
|
||||
//var Actions = require('actions/..');
|
||||
|
||||
|
||||
var <%= classedName %> = Reflux.createStore({
|
||||
listenables: Actions,
|
||||
|
||||
|
||||
});
|
||||
|
||||
<% if (es6) { %> export default <%= classedName %>; <% }
|
||||
else { %>module.exports = <%= classedName %>; <% } %>
|
||||
@@ -1,4 +0,0 @@
|
||||
var Alt = require('alt');
|
||||
var alt = new Alt();
|
||||
|
||||
module.exports = alt;
|
||||
@@ -1,18 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var <%= scriptAppName %> = require('./<%= scriptAppName %>');
|
||||
var React = require('react');
|
||||
var Router = require('react-router');
|
||||
var Route = Router.Route;
|
||||
|
||||
var content = document.getElementById('content');
|
||||
|
||||
var Routes = (
|
||||
<Route handler={<%= scriptAppName %>}>
|
||||
<Route name="/" handler={<%= scriptAppName %>}/>
|
||||
</Route>
|
||||
);
|
||||
|
||||
Router.run(Routes, function (Handler) {
|
||||
React.render(<Handler/>, content);
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
describe('<%= classedName %>', () => {
|
||||
let action;
|
||||
|
||||
beforeEach(() => {
|
||||
action = require('actions/<%= classedFileName %>.js');
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(action).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
describe('<%= classedName %>', () => {
|
||||
let React = require('react/addons');
|
||||
let <%= scriptAppName %>, component;
|
||||
|
||||
beforeEach(() => {
|
||||
let container = document.createElement('div');
|
||||
container.id = 'content';
|
||||
document.body.appendChild(container);
|
||||
|
||||
<%= scriptAppName %> = require('components/<%= scriptAppName %>.js');
|
||||
component = React.createElement(<%= scriptAppName %>);
|
||||
});
|
||||
|
||||
it('should create a new instance of <%= scriptAppName %>', () => {
|
||||
expect(component).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
// Uncomment the following lines to use the react test utilities
|
||||
// import React from 'react/addons';
|
||||
// const TestUtils = React.addons.TestUtils;
|
||||
|
||||
import createComponent from 'helpers/createComponent';
|
||||
import <%= classedName %> from 'components/<%= classedFileName %><%= reactComponentSuffix %>';
|
||||
|
||||
describe('<%= classedName %>', () => {
|
||||
let <%= classedName %>Component;
|
||||
|
||||
beforeEach(() => {
|
||||
<%= classedName %>Component = createComponent(<%= classedName %>);
|
||||
});
|
||||
|
||||
it('should have its component name as default className', () => {
|
||||
expect(<%= classedName %>Component._store.props.className).toBe('<%= classedName %>');
|
||||
});
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
describe('<%= classedName %>', () => {
|
||||
let store;
|
||||
|
||||
beforeEach(() => {
|
||||
store = require('stores/<%= classedFileName %>.js');
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(store).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -1,14 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
describe('main', () => {
|
||||
let main, component;
|
||||
|
||||
beforeEach(() => {
|
||||
main = require('components/main.jsx');
|
||||
component = main();
|
||||
});
|
||||
|
||||
it('should create a new instance of main', () => {
|
||||
expect(component).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,209 @@
|
||||
'use strict';
|
||||
let path = require('path');
|
||||
let expect = require('chai').expect;
|
||||
let assert = require('yeoman-assert');
|
||||
let helpers = require('yeoman-test');
|
||||
|
||||
describe('react-webpack:app', () => {
|
||||
|
||||
let defaultPrompts = require('../../../generators/app/prompts.js');
|
||||
let prompts = {};
|
||||
for(let p of defaultPrompts) {
|
||||
prompts[p.name] = p.default;
|
||||
}
|
||||
|
||||
let generator;
|
||||
let generatorBase = path.join(__dirname, '../../../generators/app');
|
||||
|
||||
before((done) => {
|
||||
|
||||
helpers.run(generatorBase)
|
||||
.inTmpDir()
|
||||
.withOptions({
|
||||
'skip-welcome-message': true,
|
||||
'skip-install': true
|
||||
})
|
||||
.withPrompts(prompts)
|
||||
.on('ready', (instance) => {
|
||||
generator = instance;
|
||||
})
|
||||
.on('end', done);
|
||||
});
|
||||
|
||||
describe('#config', () => {
|
||||
|
||||
it('should use "css" as default style language', () => {
|
||||
expect(generator.config.get('style')).to.equal('css');
|
||||
});
|
||||
|
||||
it('should not enable "PostCSS" by default', () => {
|
||||
expect(generator.config.get('postcss')).to.equal(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#createFiles', () => {
|
||||
|
||||
it('should generate dot files', () => {
|
||||
|
||||
assert.file([
|
||||
'.babelrc',
|
||||
'.editorconfig',
|
||||
'.eslintrc',
|
||||
'.gitignore',
|
||||
'.yo-rc.json'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate project configuration files', () => {
|
||||
|
||||
assert.file([
|
||||
'package.json'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate the webpack configuration', () => {
|
||||
|
||||
assert.file([
|
||||
'cfg/base.js',
|
||||
'cfg/dev.js',
|
||||
'cfg/dist.js',
|
||||
'cfg/test.js',
|
||||
'server.js',
|
||||
'webpack.config.js'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate required source files', () => {
|
||||
|
||||
assert.file([
|
||||
'src/actions/README.md',
|
||||
'src/components/Main.js',
|
||||
'src/components/run.js',
|
||||
'src/favicon.ico',
|
||||
'src/images/yeoman.png',
|
||||
'src/index.html',
|
||||
'src/sources/README.md',
|
||||
'src/stores/README.md',
|
||||
'src/styles/App.css'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate test configuration and basic tests', () => {
|
||||
|
||||
assert.file([
|
||||
'karma.conf.js',
|
||||
'test/components/MainTest.js',
|
||||
'test/helpers/shallowRenderHelper.js',
|
||||
'test/loadtests.js'
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('react-webpack:app non-default-prompts', () => {
|
||||
|
||||
let defaultPrompts = require('../../../generators/app/prompts.js');
|
||||
let prompts = {};
|
||||
for(let p of defaultPrompts) {
|
||||
prompts[p.name] = p.default;
|
||||
}
|
||||
|
||||
prompts.postcss = true;
|
||||
|
||||
let generator;
|
||||
let generatorBase = path.join(__dirname, '../../../generators/app');
|
||||
|
||||
before((done) => {
|
||||
|
||||
helpers.run(generatorBase)
|
||||
.inTmpDir()
|
||||
.withOptions({
|
||||
'skip-welcome-message': true,
|
||||
'skip-install': true
|
||||
})
|
||||
.withPrompts(prompts)
|
||||
.on('ready', (instance) => {
|
||||
generator = instance;
|
||||
})
|
||||
.on('end', done);
|
||||
});
|
||||
|
||||
describe('#config', () => {
|
||||
|
||||
it('should use "css" as default style language', () => {
|
||||
expect(generator.config.get('style')).to.equal('css');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#createFiles', () => {
|
||||
|
||||
it('should generate dot files', () => {
|
||||
|
||||
assert.file([
|
||||
'.babelrc',
|
||||
'.editorconfig',
|
||||
'.eslintrc',
|
||||
'.gitignore',
|
||||
'.yo-rc.json'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate project configuration files', () => {
|
||||
|
||||
assert.file([
|
||||
'package.json'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate the webpack configuration', () => {
|
||||
|
||||
assert.file([
|
||||
'cfg/base.js',
|
||||
'cfg/dev.js',
|
||||
'cfg/dist.js',
|
||||
'cfg/test.js',
|
||||
'server.js',
|
||||
'webpack.config.js'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should insert the postcss loader into the style pipes', () => {
|
||||
|
||||
assert.fileContent('cfg/base.js', 'loader: \'style-loader!css-loader!postcss-loader\'');
|
||||
assert.fileContent('cfg/base.js', 'loader: \'style-loader!css-loader!postcss-loader!sass-loader?outputStyle=expanded&indentedSyntax\'');
|
||||
assert.fileContent('cfg/base.js', 'loader: \'style-loader!css-loader!postcss-loader!sass-loader?outputStyle=expanded\'');
|
||||
assert.fileContent('cfg/base.js', 'loader: \'style-loader!css-loader!postcss-loader!less-loader\'');
|
||||
assert.fileContent('cfg/base.js', 'loader: \'style-loader!css-loader!postcss-loader!stylus-loader\'');
|
||||
});
|
||||
|
||||
it('should append the postcss function to the base config', () => {
|
||||
|
||||
assert.fileContent('cfg/base.js', ',\n postcss: function () {\n return [];\n }');
|
||||
});
|
||||
|
||||
it('should generate required source files', () => {
|
||||
|
||||
assert.file([
|
||||
'src/actions/README.md',
|
||||
'src/components/Main.js',
|
||||
'src/components/run.js',
|
||||
'src/favicon.ico',
|
||||
'src/images/yeoman.png',
|
||||
'src/index.html',
|
||||
'src/sources/README.md',
|
||||
'src/stores/README.md',
|
||||
'src/styles/App.css'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should generate test configuration and basic tests', () => {
|
||||
|
||||
assert.file([
|
||||
'karma.conf.js',
|
||||
'test/components/MainTest.js',
|
||||
'test/helpers/shallowRenderHelper.js',
|
||||
'test/loadtests.js'
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,181 @@
|
||||
'use strict';
|
||||
let path = require('path');
|
||||
let assert = require('yeoman-assert');
|
||||
let helpers = require('yeoman-test');
|
||||
|
||||
describe('react-webpack:component', () => {
|
||||
|
||||
let generatorComponent = path.join(__dirname, '../../../generators/component');
|
||||
|
||||
// List of available style types. Please add a line that says
|
||||
// testComponentWithStyle(styleTypes.KEY); to the bottom of the file
|
||||
// to run all unit tests for this filetype.
|
||||
const styleTypes = {
|
||||
css: {
|
||||
type: 'css',
|
||||
fileName: 'src/styles/Mycomponent.css',
|
||||
expandedFileName: 'src/styles/my/littleSpecial/Test.css',
|
||||
assertions: {
|
||||
componentImport: 'require(\'styles//Mycomponent.css\');',
|
||||
styleContent: '.mycomponent-component'
|
||||
}
|
||||
},
|
||||
sass: {
|
||||
type: 'sass',
|
||||
fileName: 'src/styles/Mycomponent.sass',
|
||||
expandedFileName: 'src/styles/my/littleSpecial/Test.sass',
|
||||
assertions: {
|
||||
componentImport: 'require(\'styles//Mycomponent.sass\');',
|
||||
styleContent: '.mycomponent-component'
|
||||
}
|
||||
},
|
||||
scss: {
|
||||
type: 'scss',
|
||||
fileName: 'src/styles/Mycomponent.scss',
|
||||
expandedFileName: 'src/styles/my/littleSpecial/Test.scss',
|
||||
assertions: {
|
||||
componentImport: 'require(\'styles//Mycomponent.scss\');',
|
||||
styleContent: '.mycomponent-component'
|
||||
}
|
||||
},
|
||||
less: {
|
||||
type: 'less',
|
||||
fileName: 'src/styles/Mycomponent.less',
|
||||
expandedFileName: 'src/styles/my/littleSpecial/Test.less',
|
||||
assertions: {
|
||||
componentImport: 'require(\'styles//Mycomponent.less\');',
|
||||
styleContent: '.mycomponent-component'
|
||||
}
|
||||
},
|
||||
stylus: {
|
||||
type: 'stylus',
|
||||
fileName: 'src/styles/Mycomponent.styl',
|
||||
expandedFileName: 'src/styles/my/littleSpecial/Test.styl',
|
||||
assertions: {
|
||||
componentImport: 'require(\'styles//Mycomponent.styl\');',
|
||||
styleContent: '.mycomponent-component'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a newly generated component with given name and style
|
||||
* @param {String} name Name of the component
|
||||
* @param {String} styleType Styling language to use
|
||||
* @param {Object} options Options to use for the generator
|
||||
* @param {Function} callback Test callback to run
|
||||
*/
|
||||
function createGeneratedComponent(name, styleType, options, callback) {
|
||||
helpers.run(generatorComponent)
|
||||
.withArguments([name])
|
||||
.withOptions(options)
|
||||
.on('ready', (instance) => {
|
||||
instance.config.set('style', styleType);
|
||||
})
|
||||
.on('end', callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a component with styling applied
|
||||
* @param {Object} style The style to apply (see styleTypes above)
|
||||
* @param {Object} options Options to use [optional]
|
||||
*/
|
||||
function testComponentWithStyle(style, options) {
|
||||
|
||||
// Make sure we always have options
|
||||
if(!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
describe(`When using style type "${style.type}"`, () => {
|
||||
|
||||
describe('When writing is called', () => {
|
||||
|
||||
it(`should create the react component, its ${style.type}-stylesheet and test file`, (done) => {
|
||||
createGeneratedComponent('mycomponent', style.type, options, () => {
|
||||
|
||||
assert.file([
|
||||
'src/components/MycomponentComponent.js',
|
||||
style.fileName,
|
||||
'test/components/MycomponentComponentTest.js'
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('When creating a component', () => {
|
||||
|
||||
it('should always import REACT', (done) => {
|
||||
createGeneratedComponent('mycomponent', style.type, options, () => {
|
||||
assert.fileContent('src/components/MycomponentComponent.js', `import React from 'react';`);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it(`should require the created ${style.type} file`, (done) => {
|
||||
createGeneratedComponent('mycomponent', style.type, options, () => {
|
||||
assert.fileContent('src/components/MycomponentComponent.js', style.assertions.componentImport);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should have its displayName set per default', (done) => {
|
||||
createGeneratedComponent('mycomponent', style.type, options, () => {
|
||||
assert.fileContent('src/components/MycomponentComponent.js', `displayName = 'MycomponentComponent';`);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should export the created component', (done) => {
|
||||
createGeneratedComponent('mycomponent', style.type, options, () => {
|
||||
assert.fileContent('src/components/MycomponentComponent.js', `export default MycomponentComponent`);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it(`should be possible to create components in a subfolder`, (done) => {
|
||||
createGeneratedComponent('my/little !special/test', style.type, options, () => {
|
||||
|
||||
assert.file([
|
||||
'src/components/my/littleSpecial/TestComponent.js',
|
||||
style.expandedFileName,
|
||||
'test/components/my/littleSpecial/TestComponentTest.js'
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Style', () => {
|
||||
|
||||
it(`should add the components ${style.type} class to the stylesheet`, (done) => {
|
||||
createGeneratedComponent('mycomponent', style.type, options, () => {
|
||||
assert.fileContent(style.fileName, style.assertions.styleContent);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test', () => {
|
||||
|
||||
it('should import the react component', (done) => {
|
||||
createGeneratedComponent('mycomponent', style.type, options, () => {
|
||||
assert.fileContent('test/components/MycomponentComponentTest.js', 'import MycomponentComponent from \'components//MycomponentComponent.js\';');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Run all tests for all available style types.
|
||||
testComponentWithStyle(styleTypes.css);
|
||||
testComponentWithStyle(styleTypes.sass);
|
||||
testComponentWithStyle(styleTypes.scss);
|
||||
testComponentWithStyle(styleTypes.less);
|
||||
testComponentWithStyle(styleTypes.stylus);
|
||||
|
||||
// Test stateless components (should be enough when testing with defaults)
|
||||
testComponentWithStyle(styleTypes.css, { stateless: true });
|
||||
});
|
||||
@@ -0,0 +1,2 @@
|
||||
--reporter spec
|
||||
--recursive
|
||||
@@ -1,342 +0,0 @@
|
||||
/*global describe, beforeEach, it*/
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var helpers = require('yeoman-generator').test;
|
||||
var assert = require('yeoman-generator').assert;
|
||||
var _ = require('underscore.string');
|
||||
|
||||
describe('react-webpack generator', function() {
|
||||
var react;
|
||||
var expected = [
|
||||
'src/favicon.ico',
|
||||
'src/styles/main.css',
|
||||
'src/index.html',
|
||||
'Gruntfile.js',
|
||||
'webpack.config.js',
|
||||
'karma.conf.js',
|
||||
'package.json'
|
||||
];
|
||||
var mockPrompts = {};
|
||||
var genOptions = {
|
||||
'appPath': 'src',
|
||||
'skip-install': true,
|
||||
'skip-welcome-message': true,
|
||||
'skip-message': true
|
||||
};
|
||||
var deps = [
|
||||
'../../app',
|
||||
'../../common',
|
||||
'../../component',
|
||||
'../../main'
|
||||
];
|
||||
|
||||
beforeEach(function(done) {
|
||||
helpers.testDirectory(path.join(__dirname, 'temp-test'), function(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
react = helpers.createGenerator('react-webpack:app', deps, false, genOptions);
|
||||
helpers.mockPrompt(react, mockPrompts);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('App files', function() {
|
||||
it('should generate dotfiles', function(done) {
|
||||
react.run({}, function() {
|
||||
helpers.assertFile([].concat(expected, [
|
||||
'.yo-rc.json',
|
||||
'.editorconfig',
|
||||
'.gitignore',
|
||||
'.jshintrc'
|
||||
]));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate app files', function(done) {
|
||||
react.run({}, function() {
|
||||
// TODO: Hack, no time to work out why generated
|
||||
// files not present at point of test...
|
||||
setTimeout(function() {
|
||||
helpers.assertFile(expected);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate expected JS files', function(done) {
|
||||
react.run({}, function() {
|
||||
setTimeout(function() {
|
||||
helpers.assertFile([].concat(expected, [
|
||||
'src/components/TempTestApp.js',
|
||||
'src/components/main.js'
|
||||
]));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate expected test JS files', function(done) {
|
||||
react.run({}, function() {
|
||||
// TODO: Hack, no time to work out why generated
|
||||
// files not present at point of test...
|
||||
setTimeout(function() {
|
||||
helpers.assertFile([].concat(expected, [
|
||||
'test/helpers/pack/phantomjs-shims.js',
|
||||
'test/helpers/createComponent.js',
|
||||
'test/helpers/react/addons.js',
|
||||
'test/spec/components/TempTestApp.js'
|
||||
]));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should use HMR webpack API inside of configs', function (done) {
|
||||
react.run({}, function() {
|
||||
assert.fileContent([
|
||||
['package.json', /react-hot-loader/],
|
||||
['Gruntfile.js', /hot:\s*true/],
|
||||
['webpack.config.js', /react-hot/],
|
||||
['webpack.config.js', /webpack\.HotModuleReplacementPlugin/],
|
||||
['webpack.config.js', /webpack\/hot\/only-dev-server/]
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate JS config with aliases', function(done) {
|
||||
react.run({}, function() {
|
||||
assert.fileContent([
|
||||
// style aliases
|
||||
['webpack.config.js', /resolve[\S\s]+alias[\S\s]+styles/m],
|
||||
['karma.conf.js', /resolve[\S\s]+alias[\S\s]+styles/m],
|
||||
['webpack.dist.config.js', /resolve[\S\s]+alias[\S\s]+styles/m],
|
||||
// script/components aliases
|
||||
['webpack.config.js', /resolve[\S\s]+alias[\S\s]+components/m],
|
||||
['karma.conf.js', /resolve[\S\s]+alias[\S\s]+components/m],
|
||||
['webpack.dist.config.js', /resolve[\S\s]+alias[\S\s]+components/m]
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any flux assets configured', function(done) {
|
||||
react.run({}, function() {
|
||||
assert.noFileContent([
|
||||
['package.json', /flux/],
|
||||
['package.json', /events/],
|
||||
['package.json', /object-assign/],
|
||||
['karma.conf.js', /resolve[\S\s]+alias[\S\s]+stores/m],
|
||||
['webpack.config.js', /resolve[\S\s]+alias[\S\s]+stores/m],
|
||||
['webpack.dist.config.js', /resolve[\S\s]+alias[\S\s]+stores/m]
|
||||
]);
|
||||
|
||||
assert.noFile('src/dispatcher/TempTestAppDispatcher.js');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Generator', function () {
|
||||
|
||||
it('should contain info about used style lang', function (done) {
|
||||
react.run({}, function() {
|
||||
assert.ok(react.config.get('styles-language'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('by default should use css style lang', function (done) {
|
||||
react.run({}, function() {
|
||||
assert.equal(react.config.get('styles-language'), 'css');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
var assertStyle = function (lang, done) {
|
||||
helpers.mockPrompt(react, {
|
||||
stylesLanguage: lang
|
||||
});
|
||||
react.run({}, function() {
|
||||
assert.equal(react.config.get('styles-language'), lang);
|
||||
done();
|
||||
});
|
||||
};
|
||||
|
||||
it('should use sass style lang', function (done) {
|
||||
assertStyle('sass', done);
|
||||
});
|
||||
|
||||
it('should use scss style lang', function (done) {
|
||||
assertStyle('scss', done);
|
||||
});
|
||||
|
||||
it('should use less style lang', function (done) {
|
||||
assertStyle('less', done);
|
||||
});
|
||||
|
||||
it('should use stylus style lang', function (done) {
|
||||
assertStyle('stylus', done);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('When using Flux', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
helpers.mockPrompt(react, {
|
||||
architecture: 'flux'
|
||||
});
|
||||
|
||||
react.run({}, function() {
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
it('should add flux, events, and object-assign packages', function(done) {
|
||||
assert.fileContent([
|
||||
['package.json', /flux/],
|
||||
['package.json', /events/],
|
||||
['package.json', /object-assign/]
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should add stores and actions alias to karma config', function(done) {
|
||||
assert.fileContent([
|
||||
['karma.conf.js', /resolve[\S\s]+alias[\S\s]+stores/m]
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should add stores and actions alias to webpack configs', function(done) {
|
||||
assert.fileContent([
|
||||
['webpack.config.js', /resolve[\S\s]+alias[\S\s]+stores/m],
|
||||
['webpack.dist.config.js', /resolve[\S\s]+alias[\S\s]+stores/m]
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should have a Dispatcher generated', function(done) {
|
||||
setTimeout(function(){
|
||||
assert.file('src/dispatcher/TempTestAppDispatcher.js');
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe('When generating a Component', function() {
|
||||
var generatorTest = function(name, generatorType, specType, targetDirectory, scriptNameFn, specNameFn, suffix, done) {
|
||||
var deps = [path.join('../..', generatorType)];
|
||||
genOptions.appPath = 'src';
|
||||
|
||||
var reactGenerator = helpers.createGenerator('react-webpack:' + generatorType, deps, [name], genOptions);
|
||||
|
||||
react.run([], function() {
|
||||
reactGenerator.run([], function() {
|
||||
helpers.assertFileContent([
|
||||
[path.join('src', targetDirectory, name + '.js'), new RegExp('var ' + scriptNameFn(name) + suffix, 'g')],
|
||||
[path.join('src', targetDirectory, name + '.js'), new RegExp('require\\(\'styles\\/' + name + suffix + '\\.[^\']+' + '\'\\)', 'g')],
|
||||
[path.join('test/spec', targetDirectory, 'TempTestApp' + '.js'), new RegExp('require\\(\'components\\/' + 'TempTestApp' + suffix + '\\.[^\']+' + '\'\\)', 'g')],
|
||||
[path.join('test/spec', targetDirectory, name + '.js'), new RegExp('import ' + scriptNameFn(name) + ' from \'components\/Foo', 'g')],
|
||||
[path.join('test/spec', targetDirectory, name + '.js'), new RegExp('describe\\(\'' + specNameFn(name) + suffix + '\'', 'g')]
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it('should generate a new component', function(done) {
|
||||
react.run({}, function() {
|
||||
generatorTest('Foo', 'component', 'component', 'components', _.capitalize, _.capitalize, '', done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate a subcomponent', function(done) {
|
||||
react.run({}, function() {
|
||||
var subComponentNameFn = function () { return 'Bar'; };
|
||||
generatorTest('Foo/Bar', 'component', 'component', 'components', subComponentNameFn, subComponentNameFn, '', done);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('When generating an Action', function() {
|
||||
|
||||
beforeEach(function(done){
|
||||
helpers.mockPrompt(react, {
|
||||
architecture: 'flux'
|
||||
});
|
||||
|
||||
react.run({}, function() {
|
||||
var generator =
|
||||
helpers.createGenerator(
|
||||
'react-webpack:action',
|
||||
[path.join('../../action')],
|
||||
['Test'],
|
||||
{ appPath: 'src' }
|
||||
);
|
||||
|
||||
react.run([], function() {
|
||||
generator.run([], function() {
|
||||
done();
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate a new action with tests', function(done) {
|
||||
assert.fileContent([
|
||||
['src/actions/TestActionCreators.js', /var TestActionCreators/g],
|
||||
['test/spec/actions/TestActionCreators.js', /require\('actions\/TestActionCreators.js'\)/g],
|
||||
['test/spec/actions/TestActionCreators.js', /describe\('TestActionCreators'/g]
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('When generating a Store', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
helpers.mockPrompt(react, {
|
||||
architecture: 'flux'
|
||||
});
|
||||
|
||||
react.run({}, function() {
|
||||
var generator =
|
||||
helpers.createGenerator(
|
||||
'react-webpack:store',
|
||||
[path.join('../../store')],
|
||||
['Test'],
|
||||
{ appPath: 'src' }
|
||||
);
|
||||
|
||||
react.run([], function() {
|
||||
generator.run([], function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should generate a new store with tests', function(done) {
|
||||
assert.fileContent([
|
||||
['src/stores/TestStore.js', /var TestStore/g],
|
||||
['test/spec/stores/TestStore.js', /require\('stores\/TestStore.js'\)/g],
|
||||
['test/spec/stores/TestStore.js', /describe\('TestStore'/g]
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
'use strict';
|
||||
let expect = require('chai').expect;
|
||||
|
||||
let utils = require('../../utils/config');
|
||||
let originalSettings = require('../../utils/configopts.json');
|
||||
|
||||
describe('Utilities:Config', () => {
|
||||
|
||||
describe('#getSetting', () => {
|
||||
|
||||
it('should return "null" if the key could not be found', () => {
|
||||
expect(utils.getSetting('bogus')).to.be.null;
|
||||
});
|
||||
|
||||
it('should return a settings object if it exists', () => {
|
||||
|
||||
let result = utils.getSetting('style');
|
||||
expect(result).to.be.an.object;
|
||||
expect(result).to.deep.equal(originalSettings.style);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getChoices', () => {
|
||||
|
||||
it('should return "null" if the key could not be found', () => {
|
||||
expect(utils.getChoices('bogus')).to.be.null;
|
||||
});
|
||||
|
||||
it('should return an array of choices when queried correctly', () => {
|
||||
|
||||
let result = utils.getChoices('style');
|
||||
expect(result).to.be.an.array;
|
||||
expect(result).to.deep.equal(originalSettings.style.options);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getChoiceByKey', () => {
|
||||
|
||||
it('should return "null" if the key or the setting could not be found', () => {
|
||||
|
||||
expect(utils.getChoiceByKey('bogus', 'unknown')).to.be.null;
|
||||
expect(utils.getChoiceByKey('style', 'unknown')).to.be.null;
|
||||
});
|
||||
|
||||
it('should return the configured object when it can be found', () => {
|
||||
|
||||
expect(utils.getChoiceByKey('style', 'css')).to.equal(originalSettings.style.options[0]);
|
||||
expect(utils.getChoiceByKey('style', 'less')).to.equal(originalSettings.style.options[3]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getDefaultChoice', () => {
|
||||
|
||||
it('should return "null" if the key could not be found', () => {
|
||||
expect(utils.getDefaultChoice('bogus')).to.be.null;
|
||||
});
|
||||
|
||||
it('should return the default choice when queried correctly', () => {
|
||||
|
||||
let result = utils.getDefaultChoice('style');
|
||||
expect(result).to.equal(originalSettings.style.default);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,121 @@
|
||||
'use strict';
|
||||
let expect = require('chai').expect;
|
||||
let path = require('path');
|
||||
|
||||
let utils = require('../../utils/yeoman');
|
||||
let baseDir = path.basename(process.cwd());
|
||||
|
||||
describe('Utilities:Yeoman', () => {
|
||||
|
||||
describe('#getBaseDir', () => {
|
||||
|
||||
it('should return the current run directory', () => {
|
||||
expect(utils.getBaseDir()).to.equal(baseDir);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getCleanedPathName', () => {
|
||||
|
||||
it('should return normalized paths', () => {
|
||||
|
||||
let tests = {
|
||||
'my/full œ!/path!': 'my/full/path',
|
||||
'Test': 'test',
|
||||
'I am a Test Component!': 'iAmATestComponent',
|
||||
'A very\^specialChary!@componentName with !!!': 'aVerySpecialCharyComponentNameWith'
|
||||
};
|
||||
|
||||
for(let test in tests) {
|
||||
expect(utils.getCleanedPathName(test)).to.be.equal(tests[test]);
|
||||
expect(utils.getCleanedPathName(test, 'suffix')).to.be.equal(tests[test] + 'Suffix');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getAppName', () => {
|
||||
|
||||
it('should return a js friendly application name', () => {
|
||||
let result = utils.getAppName('this is a test using % special / chars!');
|
||||
expect(result).to.be.equal('thisIsATestUsingSpecialChars');
|
||||
});
|
||||
|
||||
it('should use the current path for creating the appName if the argument is omitted', () => {
|
||||
|
||||
let resultWithoutArgs = utils.getAppName();
|
||||
let resultWithArgs = utils.getAppName(baseDir);
|
||||
|
||||
expect(resultWithoutArgs).to.be.equal(resultWithArgs);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getComponentStyleName', () => {
|
||||
|
||||
it('should return a components css className', () => {
|
||||
|
||||
let tests = {
|
||||
'my/full œ!/path!': 'path-component',
|
||||
'Test': 'test-component',
|
||||
'I am a Test Component!': 'i-am-a-test-component-component',
|
||||
'A very\^specialChary!@componentName with !!!': 'a-very-specialchary-componentname-with-component'
|
||||
};
|
||||
|
||||
for(let test in tests) {
|
||||
expect(utils.getComponentStyleName(test)).to.be.equal(tests[test]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getAllSettingsFromComponentName', () => {
|
||||
|
||||
it('should get all required information for component creation from the components name', () => {
|
||||
|
||||
let expection = {
|
||||
style: {
|
||||
webpackPath: 'styles/my/component/Test.css',
|
||||
path: 'src/styles/my/component/',
|
||||
fileName: 'Test.css',
|
||||
className: 'test-component',
|
||||
suffix: '.css'
|
||||
},
|
||||
component: {
|
||||
webpackPath: 'components/my/component/TestComponent.js',
|
||||
path: 'src/components/my/component/',
|
||||
fileName: 'TestComponent.js',
|
||||
className: 'TestComponent',
|
||||
displayName: 'MyComponentTestComponent',
|
||||
suffix: '.js'
|
||||
},
|
||||
test: {
|
||||
path: 'test/components/my/component/',
|
||||
fileName: 'TestComponentTest.js'
|
||||
}
|
||||
};
|
||||
|
||||
expect(utils.getAllSettingsFromComponentName('my/component/test')).to.deep.equal(expection);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getDestinationPath', () => {
|
||||
|
||||
it('should return the correct filesystem path for all components', () => {
|
||||
|
||||
expect(utils.getDestinationPath('test', 'action', 'Actions')).to.equal('src/actions/TestActions.js');
|
||||
expect(utils.getDestinationPath('subfolder/test', 'action', 'Actions')).to.equal('src/actions/subfolder/TestActions.js');
|
||||
|
||||
expect(utils.getDestinationPath('test', 'source', 'Source')).to.equal('src/sources/TestSource.js');
|
||||
expect(utils.getDestinationPath('subfolder/test', 'source', 'Source')).to.equal('src/sources/subfolder/TestSource.js');
|
||||
|
||||
expect(utils.getDestinationPath('test', 'store', 'Store')).to.equal('src/stores/TestStore.js');
|
||||
expect(utils.getDestinationPath('subfolder/test', 'store', 'Store')).to.equal('src/stores/subfolder/TestStore.js');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getDestinationClassName', () => {
|
||||
|
||||
it('should return the correct javascript class name for the given paths', () => {
|
||||
expect(utils.getDestinationClassName('test', 'action', 'Actions')).to.equal('TestActions');
|
||||
expect(utils.getDestinationClassName('test', 'source', 'Source')).to.equal('TestSource');
|
||||
expect(utils.getDestinationClassName('test', 'store', 'Store')).to.equal('TestStore');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,95 +0,0 @@
|
||||
'use strict';
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
module.exports = {
|
||||
rewrite: rewrite,
|
||||
rewriteFile: rewriteFile,
|
||||
appName: appName,
|
||||
capitalize: capitalize,
|
||||
capitalizeClass: capitalizeClass,
|
||||
capitalizeFile: capitalizeFile
|
||||
};
|
||||
|
||||
function rewriteFile (args) {
|
||||
args.path = args.path || process.cwd();
|
||||
var fullPath = path.join(args.path, args.file);
|
||||
|
||||
args.haystack = fs.readFileSync(fullPath, 'utf8');
|
||||
var body = rewrite(args);
|
||||
|
||||
fs.writeFileSync(fullPath, body);
|
||||
}
|
||||
|
||||
function escapeRegExp (str) {
|
||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
||||
}
|
||||
|
||||
function rewrite (args) {
|
||||
// check if splicable is already in the body text
|
||||
var re = new RegExp(args.splicable.map(function (line) {
|
||||
return '\s*' + escapeRegExp(line);
|
||||
}).join('\n'));
|
||||
|
||||
if (re.test(args.haystack)) {
|
||||
return args.haystack;
|
||||
}
|
||||
|
||||
var lines = args.haystack.split('\n');
|
||||
|
||||
var otherwiseLineIndex = 0;
|
||||
lines.forEach(function (line, i) {
|
||||
if (line.indexOf(args.needle) !== -1) {
|
||||
otherwiseLineIndex = i;
|
||||
}
|
||||
});
|
||||
|
||||
var spaces = 0;
|
||||
while (lines[otherwiseLineIndex].charAt(spaces) === ' ') {
|
||||
spaces += 1;
|
||||
}
|
||||
|
||||
var spaceStr = '';
|
||||
while ((spaces -= 1) >= 0) {
|
||||
spaceStr += ' ';
|
||||
}
|
||||
|
||||
lines.splice(otherwiseLineIndex, 0, args.splicable.map(function (line) {
|
||||
return spaceStr + line;
|
||||
}).join('\n'));
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
function capitalize(str) {
|
||||
str = String(str);
|
||||
return str[0].toUpperCase() + str.substr(1, str.length);
|
||||
}
|
||||
|
||||
function capitalizeClass(string) {
|
||||
var words = string.split('/');
|
||||
words.push(capitalize(words.pop()));
|
||||
return words.pop();
|
||||
}
|
||||
|
||||
function capitalizeFile(string) {
|
||||
var words = string.split('/');
|
||||
words.push(capitalize(words.pop()));
|
||||
return words.join('/');
|
||||
}
|
||||
|
||||
function appName(self) {
|
||||
var counter = 0, suffix = self.options['app-suffix'];
|
||||
// Have to check this because of generator bug #386
|
||||
process.argv.forEach(function (val) {
|
||||
if (val.indexOf('--app-suffix') > -1) {
|
||||
counter++;
|
||||
}
|
||||
});
|
||||
if (counter === 0 || (typeof suffix === 'boolean' && suffix)) {
|
||||
suffix = 'App';
|
||||
}
|
||||
return suffix ? self._.classify(suffix) : '';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
let config = require('./config');
|
||||
let yeoman = require('./yeoman');
|
||||
|
||||
module.exports = {
|
||||
config: config,
|
||||
yeoman: yeoman
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
'use strict';
|
||||
let opts = require('./configopts.json');
|
||||
|
||||
/**
|
||||
* Get a setting
|
||||
* @param {String} setting
|
||||
* @return {Mixed} setting or null if not found
|
||||
*/
|
||||
let getSetting = (setting) => {
|
||||
return opts[setting] !== undefined ? opts[setting] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get choices for a given setting
|
||||
* @param {String} setting
|
||||
* @return {Mixed} Result or null if nothing was found
|
||||
*/
|
||||
let getChoices = function getChoices(setting) {
|
||||
|
||||
let config = getSetting(setting);
|
||||
return config && Array.isArray(config.options) ? config.options : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the wanted choice by key
|
||||
* @param {String} setting
|
||||
* @param {String} key
|
||||
* @return {Object}
|
||||
*/
|
||||
let getChoiceByKey = (setting, key) => {
|
||||
|
||||
let choices = getChoices(setting);
|
||||
if(!choices) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let result = null;
|
||||
|
||||
for(let choice of choices) {
|
||||
|
||||
if(choice.name === key) {
|
||||
result = choice;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default choice for a config setting
|
||||
* @param {String} setting
|
||||
* @return {Mixed}
|
||||
*/
|
||||
let getDefaultChoice = (setting) => {
|
||||
let config = getSetting(setting);
|
||||
return config && config.default !== undefined && config.default.length > 0 ? config.default : null;
|
||||
}
|
||||
|
||||
// getChoices
|
||||
// getDefault
|
||||
|
||||
module.exports = {
|
||||
getSetting: getSetting,
|
||||
getChoices: getChoices,
|
||||
getChoiceByKey: getChoiceByKey,
|
||||
getDefaultChoice: getDefaultChoice
|
||||
};
|
||||
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"path": {
|
||||
"options": [
|
||||
{
|
||||
"name": "base",
|
||||
"path": "src"
|
||||
},
|
||||
{
|
||||
"name": "action",
|
||||
"path": "src/actions"
|
||||
},
|
||||
{
|
||||
"name": "component",
|
||||
"path": "src/components"
|
||||
},
|
||||
{
|
||||
"name": "image",
|
||||
"path": "src/images"
|
||||
},
|
||||
{
|
||||
"name": "source",
|
||||
"path": "src/sources"
|
||||
},
|
||||
{
|
||||
"name": "store",
|
||||
"path": "src/stores"
|
||||
},
|
||||
{
|
||||
"name": "style",
|
||||
"path": "src/styles"
|
||||
},
|
||||
{
|
||||
"name": "test",
|
||||
"path": "test"
|
||||
},
|
||||
{
|
||||
"name": "dist",
|
||||
"path": "dist"
|
||||
}
|
||||
]
|
||||
},
|
||||
"postcss": {
|
||||
"options": [
|
||||
{
|
||||
"name": "postcss",
|
||||
"value": "postcss",
|
||||
"packages": [
|
||||
{ "name": "postcss", "version": "^5.0.11" },
|
||||
{ "name": "postcss-loader", "version": "^0.8.0" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"style": {
|
||||
"options": [
|
||||
{
|
||||
"name": "css",
|
||||
"value": "css",
|
||||
"suffix": ".css"
|
||||
},
|
||||
{
|
||||
"name": "sass",
|
||||
"value": "sass",
|
||||
"suffix": ".sass",
|
||||
"packages": [
|
||||
{ "name": "sass-loader", "version": "^3.1.2" },
|
||||
{ "name": "node-sass", "version": "^3.4.2" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "scss",
|
||||
"value": "scss",
|
||||
"suffix": ".scss",
|
||||
"packages": [
|
||||
{ "name": "sass-loader", "version": "^3.1.2" },
|
||||
{ "name": "node-sass", "version": "^3.4.2" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "less",
|
||||
"value": "less",
|
||||
"suffix": ".less",
|
||||
"packages": [
|
||||
{ "name": "less-loader", "version": "^2.0.0" },
|
||||
{ "name": "less", "version": "^2.5.3" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stylus",
|
||||
"value": "stylus",
|
||||
"suffix": ".styl",
|
||||
"packages": [
|
||||
{ "name": "stylus-loader", "version": "^0.5.0" },
|
||||
{ "name": "stylus", "version": "~0.49.2" },
|
||||
{ "name": "nib", "version": "~1.0.4" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"default": "css"
|
||||
}
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
'use strict';
|
||||
|
||||
let path = require('path');
|
||||
let configUtils = require('./config');
|
||||
let _ = require('underscore.string');
|
||||
|
||||
// Needed directory paths
|
||||
const baseName = path.basename(process.cwd());
|
||||
|
||||
/**
|
||||
* Get the base directory
|
||||
* @return {String}
|
||||
*/
|
||||
let getBaseDir = () => {
|
||||
return baseName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all settings (paths and the like) from components name
|
||||
* @param {String} componentName The components name
|
||||
* @param {String} style Style language to use [optional]
|
||||
* @return {Object} Component settings
|
||||
*/
|
||||
let getAllSettingsFromComponentName = (componentName, style) => {
|
||||
|
||||
if(!style) {
|
||||
style = 'css';
|
||||
}
|
||||
|
||||
// Clean up the path and pull it to parts
|
||||
let cleanedPaths = getCleanedPathName(componentName);
|
||||
let componentParts = cleanedPaths.split('/');
|
||||
let componentBaseName = _.capitalize(componentParts.pop());
|
||||
let componentPartPath = componentParts.join('/');
|
||||
|
||||
// Get the components displayName property
|
||||
let componentFullName = _.classify(_.replaceAll(componentName, '/', '_'));
|
||||
|
||||
// Configure Styles
|
||||
let stylePaths = configUtils.getChoiceByKey('path', 'style');
|
||||
let styleSettings = configUtils.getChoiceByKey('style', style);
|
||||
|
||||
// Configure components
|
||||
let componentPath = configUtils.getChoiceByKey('path', 'component');
|
||||
|
||||
// Configure tests
|
||||
let testPath = configUtils.getChoiceByKey('path', 'test');
|
||||
|
||||
let settings = {
|
||||
style: {
|
||||
webpackPath: `styles/${componentPartPath}/${componentBaseName}${styleSettings.suffix}`,
|
||||
path: `${stylePaths.path}/${componentPartPath}/`,
|
||||
fileName: `${componentBaseName}${styleSettings.suffix}`,
|
||||
className: getComponentStyleName(componentBaseName),
|
||||
suffix: styleSettings.suffix
|
||||
},
|
||||
component: {
|
||||
webpackPath: `components/${componentPartPath}/${componentBaseName}Component.js`,
|
||||
path: `${componentPath.path}/${componentPartPath}/`,
|
||||
fileName: `${componentBaseName}Component.js`,
|
||||
className: `${componentBaseName}Component`,
|
||||
displayName: `${componentFullName}Component`,
|
||||
suffix: '.js'
|
||||
},
|
||||
test: {
|
||||
path: `${testPath.path}/components/${componentPartPath}/`,
|
||||
fileName: `${componentBaseName}ComponentTest.js`
|
||||
}
|
||||
};
|
||||
|
||||
return settings;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a cleaned path name for a given path
|
||||
* @param {String} path
|
||||
* @param {String} suffix [optional]
|
||||
* @return {String}
|
||||
*/
|
||||
let getCleanedPathName = (path, suffix) => {
|
||||
|
||||
if(!suffix) {
|
||||
suffix = '';
|
||||
}
|
||||
|
||||
// If we have filesystem separators, use them to build the full path
|
||||
let pathArray = path.split('/');
|
||||
|
||||
// Build the full components name
|
||||
return pathArray.map((path) => {
|
||||
return _.camelize(_.slugify(_.humanize(path)));
|
||||
}).join('/') + _.capitalize(suffix);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the css/less/whatever style name to use
|
||||
* @param {String} path
|
||||
* @return {String}
|
||||
*/
|
||||
let getComponentStyleName = (path) => {
|
||||
let fileName = path.split('/').pop().toLowerCase();
|
||||
return _.slugify(_.humanize(fileName)) + '-component';
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a js friendly application name
|
||||
* @param {String} appName The input application name [optional]
|
||||
* @return {String}
|
||||
*/
|
||||
let getAppName = (appName) => {
|
||||
|
||||
// If appName is not given, use the current directory
|
||||
if(appName === undefined) {
|
||||
appName = getBaseDir();
|
||||
}
|
||||
|
||||
return _.camelize(_.slugify(_.humanize(appName)));
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the wanted destination path
|
||||
* @param {String} name Name of the file
|
||||
* @param {String} type The type to use (e.g. action, store, ...)
|
||||
* @param {Suffix} suffix The suffix to use for the file (e.g. Store, Actions, ...)
|
||||
* @return {String} Final path
|
||||
*/
|
||||
let getDestinationPath = (name, type, suffix) => {
|
||||
|
||||
let cleanedPaths = getCleanedPathName(name, suffix);
|
||||
let fsParts = cleanedPaths.split('/');
|
||||
let actionBaseName = _.capitalize(fsParts.pop());
|
||||
let partPath = fsParts.join('/');
|
||||
|
||||
let fsPath = configUtils.getChoiceByKey('path', type).path;
|
||||
|
||||
let parts = [ fsPath ];
|
||||
if(partPath.length > 0) {
|
||||
parts.push(partPath);
|
||||
}
|
||||
parts.push(actionBaseName);
|
||||
let fullPath = parts.join('/');
|
||||
|
||||
return `${fullPath}.js`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the destinations class name
|
||||
* @param {String} name Name of the file
|
||||
* @param {String} type The type to use (e.g. action, store, ...)
|
||||
* @param {Suffix} suffix The suffix to use for the file (e.g. Store, Actions, ...)
|
||||
* @return {String} The javascript class name to use
|
||||
*/
|
||||
let getDestinationClassName = (name, type, suffix) => {
|
||||
|
||||
let fixedName = getDestinationPath(name, type, suffix);
|
||||
return _.capitalize(fixedName.split('/').pop().split('.js')[0]);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getBaseDir: getBaseDir,
|
||||
getAllSettingsFromComponentName: getAllSettingsFromComponentName,
|
||||
getAppName: getAppName,
|
||||
getCleanedPathName: getCleanedPathName,
|
||||
getComponentStyleName: getComponentStyleName,
|
||||
getDestinationPath: getDestinationPath,
|
||||
getDestinationClassName: getDestinationClassName
|
||||
};
|
||||
Reference in New Issue
Block a user