Docker image based on Ubuntu providing a base setup for a Phoenix+Webpack+Relay+React project, with some sugar and conventions to develop and build your own web applications.
You can also use this project without docker. See #49 for more info
We will improve docs and code including test coverage in the next releases
NOTICE: The default branch for this repo is develop. Check the README on master to see what's in the last release.
You can use this to start/learn/critic an Elixir Umbrella project with a core child Phoenix app acting as the web endpoint for core stuff and forwarding requests to /star-wars
from its router to a Star Wars example app, also a Phoenix app under the same umbrella.
The core also provides the base assets used for other umbrella children as well as functionality to build (via Webpack) assets for other children apps.
So far we've implemented the following:
- A GraphQL endpoint implemented in Elixir with Absinthe.
- Authentication using JWTs (JSON Web Tokens) via GraphQL (LoginMutation & LogoutMutation).
- Hardcoded Role based Authorization.
- StarWars GraphQL example as core's sibling Phoenix app.
- GraphiQL console.
- Some interesting React/Relay components in the client(browser), including a router.
- CSS Modules integration with Material Design Lite, now extracted to react-to-mdl.
- Testing framework for the backend (Elixir/Phoenix).
- Docs where you can find additional information about this project.
This whole Umbrella Architecture section is a WIP.
- Create umbrella
- Create Core Phoenix app inside umbrella, run it on
HTTP_PORT
making sure everything works. - Turn off Core.
- Create StarWars app inside umbrella, run it also on
HTTP_PORT
making sure everything works. - Turn off StarWars.
- Configure
Core.Mixfile
to depend on{:star_wars, in_umbrella: true}
. - Configure
Core.Router
toforward "/star-wars", StarWars.Router
. - Don't start
StarWars.Endpoint
. Comment it out in lib/star_wars.ex. - Create core/webpack.umbrella.config.js containing instructions to build one commons bundle and one bundle for each app in the umbrella.
- Define a script in core/package.json to start Webpack using webpack.umbrella.config to build & watch the assets in dev.
- Adjust watchers in core/config/dev.exs.
- Turn ON
iex -S mix phoenix.server
from the root of the umbrella making sure everything works. - Analyse and REFACTOR to architecture. After applying principles like DRY, SRP and others, now every app in the umbrella is responsible for a particular domain.
- Apps outside umbrella.
- Apps inside umbrella running simultaneously.
- Apps using its own Phoenix page layout and bundle.
- Apps using page layout from a sibling
- Other scenarios
Also talk about yarn
To run this software you need to install Docker on your system. It is very simple and there are a lot of guides and tutorials out there on the Internet.
NOTICE: this was only tested in Unix like OS (Mac OS X and Ubuntu) but it should run on Windows without major problems.
With Docker working on localhost, you can setup this project in 2 ways:
- Setup cloning this GitHub repo and build the image.
- Setup pulling Docker image from Docker Cloud repository.
With all setup, you can start the corresponding containers (aka services) by running the following command in your console:
docker-compose up
you can also just use the docker-compose.dev.example.yml file directly.
docker-compose -f docker-compose.dev.example.yml up
add
-d
to the above commands if you want them to execute in background
When the containers are all up and running, you can go inside the web app container and start the web app so you can play with it. To go inside the container execute the following command in the root directory of the project:
Assuming the files are placed in a directory named pwr2-docker and the generated container is named pwr2docker_web_1
docker exec -it pwr2docker_web_1 bash
You can see the names of running containers with the command
docker ps
on your localhost
Once inside the container, you'll need to switch to app user in order to execute Elixir/Phoenix commands. To switch to app user run:
su app
All the stuff in /home/app belongs to app user. You might experience some errors if you try to execute Elixir commands as root. Take a look at the Dockerfile to see how all the stuff is installed
Once switched to app user and in the APP_HOME
directory, you can:
- Create and migrate dev database:
mix do ecto.create, ecto.migrate
- Create and migrate test database:
MIX_ENV=test mix do ecto.create, ecto.migrate
- Run db seeds to create a superadmin dev user:
mix run apps/webapp/priv/repo/seeds.exs
. Take a look at the seeds file to get the corresponding credentials. - Start the application server:
mix phoenix.server
, or if you want to start the server in a Elixir consoleiex -S mix phoenix.server
Now you're ready to start making requests to the web app on the port you specified and try out some examples.
- Run all tests
MIX_ENV=test mix espec --trace
. - Run tests while coding, for example, to run a specfic spec:
mix test.watch spec/models/user_spec.exs --trace --focus
.
Check ESpec, ESpec.Phoenix and mix test.watch to see more info about the testing framework used in this project.
Execute docker-compose stop
in the same directory where you started them with docker-compose up ...
.
If you want to stop them when running in foreground just press CTRL+C once.
- Clone the project to your localhost (you might want to fork it to your account before)
- Copy the docker-compose.dev.example.yml to docker-compose.yml and adjust the ports and volumes.
- Build the image. In the root directory of the project execute
docker build .
- When the build finishes, tag the image to match the web image defined in your docker-compose file. For example
docker tag IMAGE_ID pwr2:latest
Now you're ready to start the containers and try some stuff.
- Open you console or terminal and execute
docker login
. You might not need this. - Pull the image from Docker Cloud. Execute
docker pull iporaitech/pwr2-docker:latest
. You can also search for other tags besides latest. - Copy the docker-compose.dev.example.yml to docker-compose.yml on your localhost and adjust the ports, volumes and image in web section to match the image tag you pulled in the step above.
Now you're ready to start the containers and try some stuff.
Once the containers are up and running you can copy the source code of the base project from the container to your localhost with the following command:
rsync -rav -e "ssh -p2224 -i insecure_key" --exclude "_build" --exclude "deps" root@localhost:/home/app/webapp/* .
Assuming you exposed the port 2224 to access the container via SSH
Notice: Tags/Releases in this GitHub repo are the equivalent to tags in the Docker Cloud repository, master is the latest image in DockerHub.
Once all setup and with the app running and assuming your HTTP_PORT
is 4000, you can:
- Login with credentials available in priv/repo/seeds.exs. Logout is also available.
- Visit http://localhost:4000/admin/graphiql to access a GraphiQL IDE.
- Visit http://localhost:4000/admin/star-wars to experiment with our implementation of the Relay Star Wars example. The database for this example is implemented as an Elixir.Agent
- You can also use something like Google Chrome's Advanced Rest Client(ARC) or any other JSON API client and (with the corresponding Authorization header) send queries to http://localhost:4000/graphql like:
{
"query": "query GetFactions($names:[String]){factions(names: $names) {id name}}",
"variables": {
"names": ["Galactic Empire", "Alliance to Restore the Republic"]
}
}
Basically, the stack is composed of server application and a Javascript client rendered in the browser.
Following a brief description of major components of this technology stack. See also the Dockerfile.
A minimal Ubuntu base image modified for Docker-friendliness. This is the base Ubuntu image for this images (see FROM
in the Dockerfile). It provides a correct init process, syslog-ng, logrotate among other stuff needed in most server installations.
Current: phusion/baseimage:0.9.19
Erlang is a programming language used to build massively scalable soft real-time systems with requirements on high availability. Some of its uses are in telecoms, banking, e-commerce, computer telephony and instant messaging. Erlang's runtime system has built-in support for concurrency, distribution and fault tolerance.
This provides the Virtual Machine(VM) on top of which Elixir and Phoenix run
Current: Erlang/OTP 19.0
Elixir is a dynamic, functional language designed for building scalable and maintainable applications.
Elixir leverages the Erlang VM, known for running low-latency, distributed and fault-tolerant systems, while also being successfully used in web development and the embedded software domain.
Current: Elixir 1.3.1
A productive web framework that does not compromise speed and maintainability.
Phoenix leverages the Erlang VM ability to handle millions of connections alongside Elixir's beautiful syntax and productive tooling for building fault-tolerant systems.
We use Phoenix as our backend programming framework
See mix.exs to check current version.
GraphQL implementation for Elixir, specifically using the packages Absinthe.Relay and Absinthe.Plug.
See mix.exs to check current versions.
Also, you might want to checkout the Relay GraphQL specifications to write GraphQL schemas to support Relay apps:
Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.
Phoenix relies on Node to compile and handle static assets.
Take a look at package.json to see all NPM packages used in this application.
Current: Node v6.3.1
webpack is a module bundler. webpack takes modules with dependencies and generates static assets representing those modules.
We use this instead of brunch.io , which is the default to compile static assets in Phoenix
Take a look at webpack.config.js to see how the loaders and plugins are configured to make things work in the front-end.
See package.json to see the current versions of these NPM packages.
Relay is a Javascript framework for building data-driven React applications.
React is a Javascript library for building user interfaces.
See package.json to see the current versions of these dependencies and other NPM packages in this project.
Check mix.exs and mix.lock to know Elixir dependencies and package.json to know about Javascript dependencies.
Inside the container in APP_HOME
directory with command mix phoenix.new --no-brunch
.
Later on, we've added Webpack and its Babel stuff; loader, presets, polyfill and runtime.
Take a look at config/dev.exs to see how we've configured a watcher for npm start
, this is how you get live reloading when editing files.
Although getting better in each release, we still find Docker for Mac volumes to be very slow. That's why we commented out the volumes configuration in the web section in the docker-compose.dev.example.yml file. Obviously, this is not a problem when running Docker on Linux.
Instead of mounting a volume to work with source code on the container we use Atom IDE with the remote-sync plugin. When this plugin is enabled everytime you save a file it gets automatically copied to the container via SSH. Probably, you might find similar or better strategies with your IDE or you local setup.
If you want to try volumes when running the image pulled directly from Docker Cloud, remember to first get the source code of this project into your localhost in the directory you want to share with the container. This is because the volumes are mounted from host to container (HOST:CONTAINER in the volumes definition in the docker-compose file). If the file don't exist in your localhost when mounting a dir they won't exist in your container in the specified directory even if they did exist in the image.
See CONTRIBUTING.md.
Anyways, just create an issue if you have any question or want something but don't know exactly what it is.
With love from Iporaitech, a small startup based in Paraguay.
This project is licensed under MIT.