Giter Club home page Giter Club logo

drupal-container's Introduction

Drupal Container (Built with Ansible)

CI Docker pulls

This project is composed of three main parts:

  • Ansible project: This project is maintained on GitHub: geerlingguy/drupal-container. Please file issues, support requests, etc. against this GitHub repository.
  • Docker Hub Image: If you just want to use the geerlingguy/drupal Docker image in your project, you can pull it from Docker Hub.
  • Ansible Role: If you need a flexible Ansible role that's compatible with both traditional servers and containerized builds, check out geerlingguy.docker on Ansible Galaxy. (This is the Ansible role that does the bulk of the work in managing the Docker container.)

Versions

Currently maintained versions include:

  • latest
  • latest-arm64
  • latest-arm32v7

Standalone Usage

The easiest way to use this Docker image is to place the docker-compose.yml file included with this project in your Drupal site's root directory, then customize it to your liking, and run:

docker-compose up -d

You should be able to access the Drupal site at http://localhost/, and if you're installing the first time, the Drupal installer UI should appear. Follow the directions and you'll end up with a brand new Drupal site!

Automatic Drupal codebase generation

The image downloads Drupal into /var/www/html if you don't have a Drupal codebase mounted into that path by default.

You can override this behavior (if, for example, you are sharing your codebase into /var/www/html/web or elsewhere) by setting the environment variable DRUPAL_DOWNLOAD_IF_NOT_PRESENT=false.

There are three methods you can use to generate a Drupal codebase if you don't have one mounted into this container (or COPYed into the container via Dockerfile):

  • DRUPAL_DOWNLOAD_METHOD=tarball (default): Downloads the latest tarball version of Drupal core.
  • DRUPAL_DOWNLOAD_METHOD=git: Clones Drupal from the git source, with options:
    • DRUPAL_CLONE_URL: The URL from which Drupal is cloned.
    • DRUPAL_CLONE_BRANCH: The branch that is checked out.
  • DRUPAL_DOWNLOAD_METHOD=composer: Creates a new Drupal project using composer create-project. If using this method, you should also override the following variables:
    • DRUPAL_PROJECT_ROOT=/var/www/html
    • APACHE_DOCUMENT_ROOT=/var/www/html/web

Drupal codebase

To get your Drupal codebase into the container, you can either COPY it in using a Dockerfile, or mount a volume (e.g. when using the image for development). The included docker-compose.yml file assumes you have a Drupal codebase at the path ./web, but you can customize the volume mount to point to wherever your Drupal docroot exists.

If you don't supply a Drupal codebase in the container in /var/www/html, this container's docker-entrypoint.sh script will download Drupal for you (using the DRUPAL_DOWNLOAD_VERSION). By default the image uses the latest development release of Drupal, but you can override it and install a specific version by setting DRUPAL_DOWNLOAD_VERSION to that version number (e.g. 9.2.1).

Settings in settings.php

Since it's best practice to not include secrets like database credentials in your codebase, this Docker container recommends putting connection details into runtime environment variables, which you can include in your Drupal site's settings.php file via getenv().

For example, to set up the database connection, pass settings like DRUPAL_DATABASE_NAME:

$databases['default']['default'] = [
  'driver' => 'mysql',
  'database' => getenv('DRUPAL_DATABASE_NAME'),
  'username' => getenv('DRUPAL_DATABASE_USERNAME'),
  'password' => getenv('DRUPAL_DATABASE_PASSWORD'),
  'prefix' => getenv('DRUPAL_DATABASE_PREFIX'),
  'host' => getenv('DRUPAL_DATABASE_HOST'),
  'port' => getenv('DRUPAL_DATABASE_PORT'),
];

You may also want to set a DRUPAL_HASH_SALT environment variable to drive the $settings['hash_salt'] setting.

Custom Apache document root

The default Apache document root is /var/www/html. If your codebase needs to use a different docroot (e.g. /var/www/html/web for Composer-built Drupal projects), you should set the environment variable APACHE_DOCUMENT_ROOT to the appropriate directory, and the container will change the docroot when it starts up.

Management with Ansible

Prerequisites

Before using this project to build and maintain Drupal images for Docker, you need to have the following installed:

Build the image

Make sure Docker is running, and run the playbook to build the container image:

ansible-playbook main.yml

# Or just build one platform version (e.g. x86):
ansible-playbook main.yml --extra-vars "{build_amd64: true, build_arm64: false, build_arm32: false}"

Once the image is built, you can run docker images to see the drupal image that was generated.

Note: If you get an error like Failed to import docker-py, run pip install docker-py.

If you want to quickly run the image and test that the docker-entrypoint.sh script works to grab a copy of the Drupal codebase, run it with:

docker run -d -p 80:80 -v $PWD/web:/var/www/html:rw geerlingguy/drupal

Then visit http://localhost/, and (after Drupal is downloaded and expanded) you should see the Drupal installer! You can drop the volume mount (-v) for a much faster startup, but then the codebase is downloaded and stored inside the container, and will vanish when you stop it.

Push the image to Docker Hub

Currently, the process for updating this image on Docker Hub is manual. Eventually this will be automated via Travis CI.

  1. Log into Docker Hub on the command line:

    docker login --username=geerlingguy
    
  2. Push to Docker Hub:

    docker push geerlingguy/drupal:latest
    docker push geerlingguy/drupal:latest-arm64
    docker push geerlingguy/drupal:latest-arm32v7
    

License

MIT / BSD

Author Information

This container build was created in 2018 by Jeff Geerling, author of Ansible for DevOps.

drupal-container's People

Contributors

geerlingguy avatar madonius avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

drupal-container's Issues

xdebug not working

I recently pulled down the latest version of the docker image and xdebug is no longer working.

After some poking around inside the image, I found out that it's because the location of "xdebug.so" has changed.

In "/etc/php/7.4/mods-available/xdebug.ini", the "zend_extension" property is pointing to "/usr/lib/php/20170718/xdebug.so".

In the latest drupal image, it should be pointing to "/usr/lib/php/20190902/xdebug.so".

Drop database connection information into settings.php file for new codebase

This way the container can be scaled to more than 1 replica in Kubernetes (see geerlingguy/raspberry-pi-dramble#111), and it can also be replaced and still use an existing database.

Basically, the entrypoint script, if it needs to download the Drupal codebase, should also copy default.settings.php over to settings.php and append environment-variable DB connection information, like:

$databases['default']['default'] = [
  'driver' => 'mysql',
  'database' => getenv('DRUPAL_DATABASE_NAME'),
  'username' => getenv('DRUPAL_DATABASE_USERNAME'),
  'password' => getenv('DRUPAL_DATABASE_PASSWORD'),
  'host' => getenv('DRUPAL_DATABASE_HOST'),
  'port' => getenv('DRUPAL_DATABASE_PORT'),
];

I also need to do a site install and see what else is added to the default settings.php—I think it also drops some sort of encryption key in there. That should be set as an env variable as well, if that's the case, with instructions for how to generate it.

Automated build/push with GitHub Actions

See how it's being done in the upstream geerlingguy/php-apache container image build process. Basically add the docker login details as protected env vars in Travis CI, then edit the .travis.yml file to do an automated push once the build is complete on the master branch.

Getting 'Failed to import the required Python library Docker SDK'

TASK [Build the x86 Docker image from the main Dockerfile.] ********************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Failed to import the required Python library (Docker SDK for Python: docker (Python >= 2.7) or docker-py (Python 2.6)) on fv-az190-719's Python /opt/hostedtoolcache/Python/3.9.5/x64/bin/python. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter, for example via `pip install docker` or `pip install docker-py` (Python 2.6). The error was: No module named 'six'"}

Lots of failed builds with the above. Not sure why, I do the install on the Actions CI environment with pip3 install ansible docker :/

Allow skipping Drupal download

Add a DRUPAL_DOWNLOAD_IF_NOT_PRESENT environment variable, which defaults to true and can be overridden to skip the download if Drupal's not present.

This is helpful when, for example, someone is using this container and stashing Drupal inside /var/www/html/web... or any other location besides /var/www/html, really.

Add automatic install in entrypoint if DRUPAL_INSTALL_IF_NOT_INSTALLED true

I never really completed #1 ... I want to make it so, if there are database credentials provided, and an env variable like DRUPAL_INSTALL_IF_NOT_PRESENT is true, then we use Drush to install Drupal... maybe?

Basically, it would take another step out of the first-use/testing order of operations for this image. Mostly, I'm thinking of how it relates to the Raspberry Pi Dramble. Right now after setting everything up, you have to run through the Drupal installer via UI to complete the Drupal installation.

Not that that's horrible or anything, it just takes a little extra time, and isn't automatic. I hate things that aren't automatic.

If Drupal is already installed (or DRUPAL_INSTALL_IF_NOT_INSTALLED is set to false), then this new code that does the installation should not be run.

ARM64 build not being pushed to Docker Hub automatically

Follow-up to #8 — when I try building all three images and pushing them via GitHub Actions, I get:

***/drupal                                   latest-arm32v7    8afdc75c6ca4   1 second ago     440MB
***/drupal                                   latest            b82210279e7e   21 minutes ago   583MB
***/php-apache                               7.4               b5403a0d28e4   16 hours ago     484MB

But there's no latest-arm64 image in there. It says it runs it in the playbook output, but I'm wondering if a Docker context is messed up since the two that do appear are built by Ansible's docker_image module, whereas the arm64 build is using the command module, and calling docker build directly. Maybe the way BuildX is installed in GitHub Actions causes a failure here.

Make container work with composer create-project for Drupal 8.8+

There are a couple more changes I'd like to make after completing #22 — with Drupal 8.8+, the recommended way to begin a new Drupal site codebase is with composer create-project, e.g.:

composer -n create-project drupal/recommended-project:^8.8@dev my-project

This is a bit different than other methods, because:

  • It's not a git checkout
  • It already has the composer install stuff done
  • The 'recommended-project' layout places the web files in a 'web/' subdir (which is how drupal-project template did/does it)

And I'd also like to add a DRUPAL_RUN_COMPOSER_INSTALL env var as part of this, for those who wish to run it after a tarball or git clone.

Fix failing Travis CI build - 'curl: (52) Empty reply from server'

Example: https://travis-ci.org/geerlingguy/drupal-container/jobs/387257782#L536-L546

...
The command "ansible-playbook main.yml" exited with 0.

$ docker run -d --name=drupal -p 8080:80 geerlingguy/drupal:latest /usr/sbin/apache2ctl -D FOREGROUND
cec66b2fe4db64545d6210db049aa8607d270259c58aecb0f768405f15b4bcfc
The command "docker run -d --name=drupal -p 8080:80 geerlingguy/drupal:latest /usr/sbin/apache2ctl -D FOREGROUND" exited with 0.

$ curl http://localhost:8080/
curl: (52) Empty reply from server

The command "curl http://localhost:8080/" exited with 52.

apt-get update causes errors. makes image unusable on intel Mac

If I run the command:

docker run -it geerlingguy/drupal:latest bash

And then run apt-get update in the container session I get this as a result:

Get:1 http://deb.debian.org/debian buster InRelease [122 kB]
Get:2 http://security.debian.org/debian-security buster/updates InRelease [65.4 kB]
Get:3 https://packages.sury.org/php buster InRelease [6837 B]
Get:4 http://deb.debian.org/debian buster-updates InRelease [51.9 kB]
Err:3 https://packages.sury.org/php buster InRelease
  At least one invalid signature was encountered.
Err:2 http://security.debian.org/debian-security buster/updates InRelease
  At least one invalid signature was encountered.
Err:1 http://deb.debian.org/debian buster InRelease
  At least one invalid signature was encountered.
Err:4 http://deb.debian.org/debian buster-updates InRelease
  At least one invalid signature was encountered.
Reading package lists... Done
W: GPG error: https://packages.sury.org/php buster InRelease: At least one invalid signature was encountered.
E: The repository 'https://packages.sury.org/php buster InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
W: GPG error: http://security.debian.org/debian-security buster/updates InRelease: At least one invalid signature was encountered.
E: The repository 'http://security.debian.org/debian-security buster/updates InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
W: GPG error: http://deb.debian.org/debian buster InRelease: At least one invalid signature was encountered.
E: The repository 'http://deb.debian.org/debian buster InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
W: GPG error: http://deb.debian.org/debian buster-updates InRelease: At least one invalid signature was encountered.
E: The repository 'http://deb.debian.org/debian buster-updates InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.

Consider adding git for composer flexibility?

When I was doing some testing today, for some reason the install of the dependency of drupal coder module was trying to use git instead of downloading the zip. And because git was not available, it failed.

So maybe install git? I hate adding more and more deps though.

DocumentRoot can keep getting tons of additional /web dirs tacked on

After a few restarts (e.g. docker stop && docker start), my container's vhosts.conf starts looking like:

# cat vhosts.conf 
DirectoryIndex index.php index.html

<VirtualHost *:80>
  ServerName local.dev
  DocumentRoot "/var/www/html/web/web/web/web"

  <Directory "/var/www/html/web/web/web/web">
    AllowOverride All
    Options -Indexes +FollowSymLinks
    Require all granted
  </Directory>
</VirtualHost>

Obviously need a little more intelligence with the overwriting of the DocumentRoot! Probably need to use the ending " as a marker or something.

This happens if you set the APACHE_DOCUMENT_ROOT to something like /var/www/html/anything-here.

Related to #18.

ARM is running with PHP 7.3, but MySQL PDO extension is built for PHP 7.2

Can dig up the logs if additional information is needed. Was getting "The website encountered an unexpected error. Please try again later." when visiting cluster.pidramble.test.

It was a mysql connection error message - googling said to install php-mysql, and I saw that it was installed for php7.2

php7.2-common:armhf php7.2-dev:armhf php7.2-gd:armhf php7.2-curl:armhf php7.2-imap:armhf php7.2-json:armhf php7.2-opcache:armhf php7.2-xml:armhf php7.2-mbstring:armhf php7.2-mysql:armhf php7.2-zip:armhf php-apcu:armhf \
.
Checked the running version of php and it was on 7.3 within the docker container.
(logged into docker and put phpinfo in root folder)

Tried to a2dimod php7.3 / a2enmod php7.2, except there wasn't a php7.2 apache module available.

APACHE_DOCUMENT_ROOT can result in incorrect docroot

Because I'm overwriting both sites-enabled and sites-available, the vhost can get double-replaced, resulting in something like:

DocumentRoot "/var/www/html/web/web"

When I set APACHE_DOCUMENT_ROOT=/var/www/html/web.

D'oh!

Install Drupal if it's not already installed?

Not sure if I want to do this or not; people already have the official library Docker Drupal image on Docker Hub which has a preinstalled copy of Drupal baked in.

But if so, in entrypoint, I would have something like:

  1. If no index.php in webroot (/var/www/web/index.php).
  2. Create Drupal project in /var/www with composer create-project.

drupal/core 8.8.6 requires ext-dom

Trying to setup raspberry-pi-dramble on 4 rpi 4s. I have been successful in Provisioning the Pis up to the point where the drupal nodes get configured. The two drupal nodes are in "CrashLoopBackOff" status.

pi@kube1:~ $ kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
default nfs-client-provisioner-7b57746cd-pg2n8 1/1 Running 3 27h
drupal drupal-54856bf894-rxckw 0/1 CrashLoopBackOff 19 79m
drupal drupal-54856bf894-vnxxc 0/1 CrashLoopBackOff 19 79m
drupal mysql-8bbdcb879-vbq8m 1/1 Running 3 27h
kube-system coredns-5c98db65d4-jbmhn 1/1 Running 4 45h
kube-system coredns-5c98db65d4-tkds6 1/1 Running 5 45h
kube-system etcd-kube1 1/1 Running 4 45h
kube-system kube-apiserver-kube1 1/1 Running 4 45h
kube-system kube-controller-manager-kube1 1/1 Running 4 45h
kube-system kube-flannel-ds-arm-4rh25 1/1 Running 5 45h
kube-system kube-flannel-ds-arm-777ks 1/1 Running 5 45h
kube-system kube-flannel-ds-arm-qn6rc 1/1 Running 2 27h
kube-system kube-flannel-ds-arm-tvhwj 1/1 Running 5 45h
kube-system kube-proxy-8dtck 1/1 Running 4 45h
kube-system kube-proxy-ksk4d 1/1 Running 4 45h
kube-system kube-proxy-wc8sx 1/1 Running 2 27h
kube-system kube-proxy-z72b6 1/1 Running 4 45h
kube-system kube-scheduler-kube1 1/1 Running 4 45h
kube-system metrics-server-f948cd54-wkzdk 1/1 Running 4 45h
kube-system traefik-ingress-controller-6zzzn 1/1 Running 3 27h
kube-system traefik-ingress-controller-pxhd2 1/1 Running 2 27h
kube-system traefik-ingress-controller-z82vm 1/1 Running 3 27h
registry docker-registry-7c68c86677-8rfcb 1/1 Running 3 27h

The problem seems to be with drupal/core 8.8.6 requiring ext-dom per the logs:

kubectl logs --follow pods/drupal-54856bf894-vnxxc -n drupal
Removing any existing files inside /var/www/html...
Downloading Drupal...
Download complete!
Configuring settings.php with environment variables...
Correcting permissions on /var/www...
Running composer install...
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Your requirements could not be resolved to an installable set of packages.

Problem 1
- drupal/core 8.8.6 requires ext-dom * -> the requested PHP extension dom is missing from your system.
- drupal/core 8.8.6 requires ext-dom * -> the requested PHP extension dom is missing from your system.
- Installation request for drupal/core 8.8.6 -> satisfiable by drupal/core[8.8.6].

To enable extensions, verify that they are enabled in your .ini files:
- /etc/php/7.4/cli/php.ini
- /etc/php/7.4/cli/conf.d/10-opcache.ini
- /etc/php/7.4/cli/conf.d/10-pdo.ini
- /etc/php/7.4/cli/conf.d/20-apcu.ini
- /etc/php/7.4/cli/conf.d/20-calendar.ini
- /etc/php/7.4/cli/conf.d/20-ctype.ini
- /etc/php/7.4/cli/conf.d/20-exif.ini
- /etc/php/7.4/cli/conf.d/20-ffi.ini
- /etc/php/7.4/cli/conf.d/20-fileinfo.ini
- /etc/php/7.4/cli/conf.d/20-ftp.ini
- /etc/php/7.4/cli/conf.d/20-gettext.ini
- /etc/php/7.4/cli/conf.d/20-iconv.ini
- /etc/php/7.4/cli/conf.d/20-json.ini
- /etc/php/7.4/cli/conf.d/20-phar.ini
- /etc/php/7.4/cli/conf.d/20-posix.ini
- /etc/php/7.4/cli/conf.d/20-readline.ini
- /etc/php/7.4/cli/conf.d/20-shmop.ini
- /etc/php/7.4/cli/conf.d/20-sockets.ini
- /etc/php/7.4/cli/conf.d/20-sysvmsg.ini
- /etc/php/7.4/cli/conf.d/20-sysvsem.ini
- /etc/php/7.4/cli/conf.d/20-sysvshm.ini
- /etc/php/7.4/cli/conf.d/20-tokenizer.ini
You can also run php --ini inside terminal to see which files are used by PHP in CLI mode.

Could this be related to geerlingguy/drupal-vm#1962 ? If so any ideas on how to fix?

Thanks

Zip / unarchive utility is not present on ARM build

In a similar vein to #10 - without unzip / untar utilities, composer doesn't do a whole lot (especially without git as well.

I just ran a composer require and got:

# composer require drush/drush
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Using version ^9.5 for drush/drush
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 26 installs, 0 updates, 0 removals
    Failed to download webmozart/assert from dist: The zip extension and unzip command are both missing, skipping.
Your command-line PHP is using multiple ini files. Run `php --ini` to show them.
    Now trying to download from source
  - Installing webmozart/assert (1.4.0): Cloning 83e253c8e0

                                                                                                                       
  [RuntimeException]                                                                                                   
  Failed to clone https://github.com/webmozart/assert.git, git was not found, check that it is installed and in your   
  PATH env.                                                                                                            
                                                                                                                       
  sh: 1: git: not found 

So I should install an unzip-like utility in the ARM build so it works with Composer commands.

Build new arm64 version

The Raspberry Pi foundation just released a beta of the Raspberry Pi OS 64-bit version, and it uses arm64 instead of armv7l, so I'd like to build a new tag version for arm64. See related: geerlingguy/drupal-pi#45

begin tagging releases

Currently there is only a latest tag pushed to docker hub. In light of #34 it would be nice if we had some old tags to pin releases to.

Default to Drupal 9

Currently this container's entrypoint will download or install Drupal 8.x:

DRUPAL_CLONE_BRANCH=${DRUPAL_CLONE_BRANCH:-"8.8.x"}
DRUPAL_PROJECT_VERSION=${DRUPAL_PROJECT_VERSION:-"^8@dev"}

These defaults should be changed to the Drupal 9 equivalents.

Build and maintain arm32v7 version that is Raspberry Pi compatible

See closed issue geerlingguy/php-apache-container#5 and downstream issue geerlingguy/raspberry-pi-dramble#119

Basically, I want to use this image on a Raspberry Pi, so I need a pi-compatible (arm32v7) image tagged. I would love to do a proper multi-arch image with all PHP versions, but that would be excruciatingly difficult to maintain correctly.

Therefore I'm thinking I'll do one Pi-based build (built on my Mac for now, but can also be built using QEMU and/or on a Pi directly) and tag it with :latest-pi or something like that.

ARM is running PHP 7.0.33, has failures with modern Drupal installs

Sadly, PHP 7.0.33 no longer allows installation of Drupal from a Composer codebase using Drush... therefore I'd like to upgrade.

Debian/Raspbian Buster has PHP 7.2... so for now that might be the path of least resistance. Also need to switch from mysql-client to mariadb-client though.

Allow setting trusted host settings

Since I hate seeing warnings on the site Reports page... it would be nice to be able to use an environment variable like DRUPAL_TRUSTED_HOSTS to drive an optional config section in settings.php to squelch the warning on the Reports page (and, well, for slightly improved site security!).

Other settings.php things...

So after a brand new Drupal 8 install, the installer places the following into settings.php:

$databases['default']['default'] = array (
  'database' => 'drupal',
  'username' => 'drupal',
  'password' => 'drupal',
  'prefix' => '',
  'host' => 'mysql',
  'port' => '3306',
  'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
  'driver' => 'mysql',
);
$settings['install_profile'] = 'standard';
$config_directories['sync'] = 'sites/default/files/config_8NvXCF2EiIMtDf7_v7H0PXFW_YnwVvlTcNARpqpmcKjFcPK1GjFWpszwF-A4MXa9GlK2Q6lDFw/sync';

Should we support more things being included at runtime? I'm trying to find a way to make all this stuff as automatable as possible for:

  • First time setup with no Drupal available (e.g. for Pi Dramble use case: geerlingguy/raspberry-pi-dramble#104).
  • Ongoing Drupal container build support: ideally also with the ability to set some things different if running locally, or in dev/stage vs prod, that sort of thing.

It seems like 99% of the Drupal containers out there are built for local dev only. Nobody really shares how they do Docker + Drupal in production. Maybe nobody really does? Or they all mount volumes for the codebase? (ICK!).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.