#Optcli
Note: This is an alternative implementation of the Funnel Envy's optcli tool. Rather than being a stand-alone tool, this generator makes use of readily available open source tools.
Optcli is a set of tools used by developers to create and manipulate Optimizely experiments on their local machines in addition to using the Optimizely web interface.
By developing locally, you are free to use whichever tools you want -- text editors, IDEs, and even precompilers.
In addition to developing locally, optcli adds a number of optional features that make test development easier and more efficient.
##Recent ChangeLog ###0.1.0
- Remove ES6 support (considering Typescript instead)
- Modify folder structure
- Overhaul templating system
- template function replaces templates object in ejs context
- template function produces an array of strings instead of a flat string
- templates function can take a locals variable for rendering
- "Import" js from in includes folder
- Removed strings.json functionality. (Add data to package.json instead)
- Incorporated '*-advanced' functionality into 'regular' generators
##Introduction
Optcli, much like the Yeoman project that inspired it, optcli is built on a set of open source tools.
-
yo -- yo is a scaffolding tool used to create projects, experiments, and variations on your local machine.
- generator-optcli -- yo uses the optcli generator to create a directory of local files and folders that can be hosted locally and/or pushed to Optimizely. It also creates a task runner file used in conjunction with gulp that's responsible for hosting variations locally and pushing content to Optimizely.
-
gulp -- gulp is a tasks runner that's used to preform tasks associated with your experiment. It is used to host files locally, and push files to Optimizely. It is also used to facilitate the optional features mentioned above. Support is planned for other task runners including grunt and brocoli.
##Installation
###Prerequesites
To install optcli, first you must download and run the node installer from https://nodejs.org/. Node is a runtime that the optcli application requires.
Second, you'll need npm, a package manager that makes it easy to install runtime components. It's installed alongside node by default, so you can likely ignore this step.
(Note : Some users that have installed node via methods other than the one above have had issues using yo. For best results, please install/update you node installation only via downloading the installer from nodejs.org )
###Components
Once the prerequisites have been installed, on your command line, enter the following command in your terminal to install all necessary components:
npm install -g yo generator-optcli gulp
You now have all the necessary components installed to start working.
yo optcli:<generator>
###Generator -- Project
Create an optcli Project from within any directory. Yo can crate a project in any directory on your system.
yo optcli:project
###Generator -- Experiment
Create an optcli Experiment within a project directory. Ensure that you are within an project directory before using.
yo optcli:experiment
###Generator -- Variation
Create an optcli Variation within an experiment directory Ensure that you are within an experiment directory before using
yo optcli:variation
####Taskrunner The experiment generator allows you to optionally create a taskrunner file. Currently, this is a gulp file, but there are plans to support other taskrunners in the future.
The generated gulpfile's default tag facilitates the following features:
- Stylesheet Pre-procesing
- Javascript File Concatination
- templating
Edit the files within the experiment directory and run the command
gulp
or
gulp default
to transpile them into global.js, global.css, and variation.js files for hosting and pushing to optiizly.
#####Stylesheet Pre-processing You can choose to use less or scss instead of plain css. In addition, files are auto-prefixed to help ensure compatibility.
#####Javascript File Concatination Files in the folder _/includes folder will be incorporated into the mail global.js file.
_/includes/jayquery.js
window.$ = function(){
alert('this is not jquery');
return undefined;
}
_/global.js
var crucialDomObject = $('.pleaseBeThere');
_/global.js
window.$ = function(){
alert('this is not jquery');
return undefined;
}
var crucialDomObject = $('.pleaseBeThere');
#####Templating Each file script and style is processed as an EJS file. The ejs context contains specific objects:
- template - this function takes the name of a file from ./_/assets/templates and returns an array of strings representing its lines. It takes a second, optional parameter to be passed as a separate ejs context
- templateArray - This function is a mask for the template function which will additionally return the template as a formatted array that can be directly set as a javascript variable.
- hx - this function takes a string and hashes it. Can be useful for creating classes that avoid collisions with other experiments.
- package - this object contains the contents of package.json
- experiment - this object contains the context of experiment.json
- variation - per variations, this object contains the contents of variation.json. Note: this is only available when processing a _variation.js file into a variation.js file. In other contexts, this will throw an error.
######Template Usage : Incorporate Experiment Data You Experiment data is a often useful. Why not incorporate it into the experiment itself?
These files:
experiment.json
{
"description":"Title Test"
}
0/variation.json
{
"description":"First Title"
}
1/variation.json
{
"description":"Second Title"
}
_global.js
console.log("Experiment Running: <%= experiment.description%>")
0/_variation.js
$('title').text("<%= variation.description%>");
1/_variation.js
$('title').text("<%= variation.description%>");
, once processed will become:
global.js
console.log("Experiment Running: Title Test")
0/variation.js
$('title').text("First Title");
1/variation.js
$('title').text("Second Title");
You can also include custom data from package.json:
The files:
//package.json
{
...
"logo":"logo.png"
}
0/_variation.js
$('img').href("<%= package.logo %>");
, once processed will become:
0/_variation.js
$('img').href("logo.png");
######Template Usage : Build UI Elements Files in the _/assets/templates/ folder are incorporated into the ejs context by passing it's base file name into the template function.
The files:
_/assets/templates/logobox.html
<div>
<img src=\"logo.png\" />
</div>
0/_variation.js
var logobox = <%- templateArray('logobox.html') %>;
$('body').append(logobox);
, once processed will become:
0/variation.js
var logobox = ["<div>"," <img src='logo.png' />","</div>"].join('');
$('body').append(logobox);
By passing in a locals object as the second argument to template fliles can be processes as ejs files in a separate context:
The files:
_/assets/templates/logobox.html
//package.json { ... "logo":"logo.png" }
<div>
<img src=\"<%= logo %>\" />
</div>
0/_variation.js
var logobox = [''<% template('logobox.html', {logo:package.logo}).forEach(function(line){ %>
,'<%- line %>'<%})%>].join('\n');
$('body').append(logobox);
, once processed will become:
0/variation.js
var logobox = [''
,"<div>",
," <img src=\"logo.png\" />",
,"</div>"].join('');
$('body').append(logobox);
Alternatively, the files:
_/assets/templates/logobox.html
<div>
<img src=\"logo.png\" />
</div>
0/_/variation.js
var logobox = '\
<% template("logobox.html").forEach(function(line){ %>
<%- line + '\\'%><%})%>\';
'
will produce:
0/variation.js
var logobox = '\'
<div>\
<img src=\"logo.png\" />\
</div>';
However; note the trailing "'" here. It will cause an error if used in the code, but it's to preserve syntax highlighting in this document, as most parsers have a hard time handling the specified content above. For this reason, you are discouraged from incorporating templates in this way.
######Template Usage : Ensure Unique Classnames
Use the hash function in order to ensure unique class names in your style code.
/global.css
.popup .button{
}
/*this may cause issues if something else decides to use the name 'popup'*/
_/global.css
.cls<%=hx('popup')%> .button{
}
/*this will produce a unique string of characters unique to the experiment,
unlikely to cause collisions*/
####Gulp Tasks Other than the default tasks, we've included a few other tasks for your convinience:
Running this task is exactly like running the default task, except it will recompile your _ folders whenever files are changed. It will also recompile whenever your package.json, experiment.json, or variation.json files are changed.
Example:
gulp watch
This task ensures that your code conforms to good coding practices
Example:
gulp lint
Gulp push requires exactly one of three flags to work.
The experiment flag will push an experiment from a given directory
Example:
gulp push --experiment
The variation flag will push a variation from a given directory
gulp push --variation output/Default\ Variation
The all flag will push an experiment from a given directory AND variations created in subdirectories
gulp push --all output
Running this task will host your local variations Gulp host runs localghost externally
Use the variation flag to specify the directory of the variation being hosted. This is mandatory. You probably want to point this to your output folder.
gulp host --variation output/<path to variation>
Using this flag will cause the hosted variation to refresh whenever files are changed.
gulp host --live --variation output/<path to variation>
(NOTE: this section could use some improvement)
Once you've started hosting, you can visit http://localhost:8080 or (https://localhost:8080 if your experiment's edit url is uses https).
This page will help you to install the userscript associated with optcli
The gulp file is designed to look at your projects url and determine if it should be hosted using ssl or not. Hosting changes to a secure site may not initially work. If this happens, visit https://localhost:8080 and tell your browser to allow you to visit the site.
MIT