Skip to content
This repository has been archived by the owner on Mar 30, 2024. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Matt Karl committed Oct 13, 2014
0 parents commit 1c243d4
Show file tree
Hide file tree
Showing 34 changed files with 1,072 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
*.map
109 changes: 109 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Node Webkit Application Initializer

Node plugin for creating scaffolding necessary to start a new node-webkit application. This creates the project structure need to build Windows and OSX Applications. It also will package your application into a sexy and simple setup installer DMG or EXE. Initialized application automatically include [Bootstrap](http://getbootstrap.com/) and [JQuery](http://jquery.com).

## Installing

Install this node module globally.

```bash
npm install -g nw-init
```

## Usage

Give a path to the new project folder. If no path is set, it will install in the current working directory.

```bash
nw-init ~/Desktop/MyNewApp
```

## Dependencies

In order to build your new application, there are some external global dependencies that are required.

### grunt

Grunt is required to build. See the [getting started guide](http://gruntjs.com/getting-started).

```bash
npm install -g grunt-cli
```

### makensis

[makensis](http://nsis.sourceforge.net/Main_Page) is required to create the Windows setup executable. Can be installed with [brew](http://brew.sh/):

```bash
brew install makensis
```

### appdmg

[node-appdmg](https://github.com/LinusU/node-appdmg) is required to create the OS X DMG installer image.

```bash
npm install -g appdmg
```

### wine

On OSX if building for Windows, Wine needs to be installed to create the application icon. Can be installed with [brew](http://brew.sh/)

```bash
brew install wine
```

## Building

The Grunt project is an extension of the [grunt-game-builder](https://github.com/CloudKidStudio/grunt-game-builder) and all those grunt tasks can be used on your app. In addition, there are several Grunt tasks that are specific and useful to building your node-webkit application:

Task | Description
---|---
**app** | Builds a release version of the node-webkit app
**app-debug** | Builds a debug version of the node-webkit app
**package** | Create the OSX and Windows installers
**open** | Open the OSX application

### Examples

Build the application in debug mode and run:

```bash
grunt app-debug open
```

Build the release application and package to installers:

```bash
grunt app package
```

## Conditional Compiling

In addition to `grunt-game-builder`'s `DEBUG` and `RELEASE` condititional constants for JavaScript, applications created with nw-init support `APP` and `WEB`.

```js

if (APP)
{
// Only app builds will show this code
var fs = require('fs');
fs.readFile('data.json', function(err, data){
data = JSON.parse(data);
// load a json file with node
});
}

if (WEB)
{
// Only default builds, like grunt tasks 'build' and 'build:dev'
$.getJSON('data.json', function(data){
// load a json file with jQuery
});
}
```

##License

MIT License
247 changes: 247 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
#!/usr/bin/env node

// Include needed packages
var prompt = require('prompt'),
fs = require('fs'),
path = require('path'),
replace = require('replace'),
glob = require("glob"),
latest = require('latest'),
mkdirp = require('mkdirp').sync,

// The package json info
p = require('./package.json'),

// The result from the commandline prompting
promptResult = {},

// The folder where we will install to
// can either use the first argument or the current directory
destFolder = path.resolve(process.argv[2] || "."),

// The folder for the template source files
sourceFolder = path.join(__dirname, 'template_source');

// We'll do this once we publish to check for a new version
latest.checkupdate(p, function(code, message){
console.log(message);
(code === 0) ? start() : process.exit(code);
});

/**
* Start by asking the user for their choices
* @method start
*/
function start()
{
// Create the folder if it doesn't exist
if (!fs.existsSync(destFolder))
{
mkdirp(destFolder);
}

var files = fs.readdirSync(destFolder);

if (files.length > 1)
{
console.error("Please only run this on an empty folder.".red);
process.exit(1);
}

// Start the prompt
prompt.start();

// Get properties from the user
var schema = {
properties:
{
appName:
{
description: "App name".magenta,
type: 'string',
default: 'MyApp',
pattern: /^[a-zA-Z0-9]+$/,
message: 'App name must be only letters/numbers',
required: true
},
appDescription:
{
description: "App description".magenta,
type: 'string',
default: '',
required: false
},
appNamespace:
{
description: "App namespace".magenta,
type: 'string',
default: 'myapp',
pattern: /^[a-zA-Z0-9]+$/,
message: 'Namespace must be only letters/numbers',
required: true
},
githubRepo:
{
description: "GitHub repository URL".magenta,
type: 'string',
default: 'https://github.com/username/MyApp',
pattern: /^https\:\/\/github\.com\/[a-zA-Z0-9\-\_]+\/[a-zA-Z0-9\-\_]+$/,
message: 'Must be a valid repository URL',
require: true
},
authorName:
{
description: "Name of author".magenta,
type: 'string',
default: 'MyCompany',
pattern: /^[a-zA-Z0-9\_\-]+$/,
message: 'Author name must be only letters/numbers',
require: true
}
}
};

prompt.get(schema, function(err, result){
promptResult = result;
copyFilesToDestination();
});
}

/**
* After we have asked the user for their choices,
* we copy the files in to place
* @method copyFilesToDestination
*/
function copyFilesToDestination()
{
//ncp is a recursive copy
var ncp = require('ncp').ncp;

ncp(sourceFolder, destFolder, function(err){
if (err)
{
console.error(("Error copying:" + err).red);
process.exit(1);
}
console.info("Done copying files.".cyan);
doSearchAndReplace();
});
}

/**
* To a a search in replace on the files
* @method doSearchAndReplace
*/
function doSearchAndReplace()
{
console.info("Search and replace...".cyan);

// now do a search and replace
// first replace IN files

var replaceObj = {
"_AppName_": promptResult.appName,
"_AuthorName_" : promptResult.authorName,
"_AppDescription_" : promptResult.appDescription,
"_namespace_": promptResult.appNamespace,
"_githubRepo_" : promptResult.githubRepo
};

//text in files
var searchString;
var replaceString;

for (searchString in replaceObj)
{
replaceString = replaceObj[searchString];
replace({
regex: searchString,
replacement: replaceString,
paths: [destFolder],
recursive: true,
silent: true
});
}

console.info("Done searching in files.".cyan);

var dir;
var filename;
var newFilename;

// now folder names (we have to do folders and file
// as two separate operations due to the issue of
// renaming a file's parent folder)
var pattern = destFolder + "/**/*/";
glob(pattern, function(err, files){
processGlob(files, replaceObj);

//now file names
pattern = destFolder + "/**/*";
glob(pattern, function(err, files){
processGlob(files, replaceObj);
setupDone();
});
});
}

/**
* takes an array of files and a dictionary of {search: replace}
* and renames the files it finds whose name contains the key
* @method processGlob
* @param {Array} files Array of files from a glob pattern
* @param {Object} replaceObj Associative array of {searchString: replaceString}
*/
function processGlob(files, replaceObj)
{
files.forEach(function(file) {
var dir = path.dirname(file);
var filename = path.basename(file);

for (var searchString in replaceObj)
{
var replaceString = replaceObj[searchString];
if (filename.indexOf(searchString) > -1)
{
var newFilename = filename.replace(searchString, replaceString);
fs.renameSync(file, dir + "/" + newFilename);
}
}
});
}

/**
* The initial setup of the project is complete, everything
* from here on out should be good, but we'll try to do
* an npm install anyways.
* @method setupDone
*/
function setupDone()
{
var cwd = process.cwd();
process.chdir(destFolder);

var npm = require("npm");
npm.load(npm.config, function(err){

// Check for errors
if (err)
{
process.chdir(cwd);
console.log(err.red);
process.exit(1);
}

// Install packages in package.json
npm.commands.install([], function(){
process.chdir(cwd);
console.info("Setup done.".cyan);
process.exit();
});

npm.on("log", function(message){
// log the progress of the installation
console.log(message);
});
});
}
31 changes: 31 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "nw-init",
"version": "0.0.1",
"description": "Provides scaffolding for node-webkit applications",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/CloudKidStudio/nw-init"
},
"author": "Matt Karl",
"license": "MIT",
"bugs": {
"url": "https://github.com/CloudKidStudio/nw-init/issues"
},
"homepage": "https://github.com/CloudKidStudio/nw-init",
"dependencies": {
"decompress": "^2.0.0",
"glob": "^4.0.6",
"latest": "^0.1.2",
"ncp": "^1.0.0",
"prompt": "^0.2.14",
"replace": "^0.3.0",
"mkdirp": "^0.5.0"
},
"bin": {
"nw-init": "index.js"
}
}
3 changes: 3 additions & 0 deletions template_source/.bowerrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"directory" : "components"
}
Loading

0 comments on commit 1c243d4

Please sign in to comment.