To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

Commit 192019b9 authored by Luzian Bieri's avatar Luzian Bieri
Browse files

initial commit, added jsboilerplate

parents
# This Dockerfile uses a multi-stage build. Only the first stage requires
# all dependencies, the final image will contain only the output files
# First stage: Build project
FROM node as build
# Copy files and install dependencies
COPY ./ /
RUN npm install
RUN npm audit fix
# Build project
RUN npm run build
# Second stage: Server to deliver files
FROM nginx:1.15-alpine
# Copy files from first stage
COPY --from=build /index.html /var/www/
COPY --from=build /dist /var/www/dist
# Copy nginx configuration
COPY nginx.conf /etc/nginx/conf.d/default.conf
MIT License
Copyright (c) 2018 Alexander Dietmüller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# AMIV .js Template
A boilerplate containing essential build tools. It uses
[Webpack](https://webpack.js.org) and includes the
[Webpack Dev Server](https://github.com/webpack/webpack-dev-server) with
hot-reloading for easy development and [Babel](https://babeljs.io),
[UglifyJS](http://lisperator.net/uglifyjs/) and a optimized production config
for Webpack to build transpiled, minified `.js` files along with gzipped files.
Furthermore [ESLint](https://eslint.org), preconfigured to use the
Airbnb rules, is provided to check your code. (Feel free to adjust
`.eslintrc` to you needs)
Finally, a `Dockerfile` is included that uses a two-stage build to create
a final image that only contains the built files and the small
[http-server](https://www.npmjs.com/package/http-server), which can server
the files (and the gzipped versions) and nothing else, ready to deploy
in any cluster.
Contrary to other boilerplates, *only* build tools are included, and you
are free to choose whatever framework you like and get started quickly!
This version of the boilerplate is based on
[webpack-babel-eslint](https://github.com/NotSpecial/webpack-babel-eslint)
and contains additional files to support AMIV OAuth and the gitlab CI.
## Setup
Clone this repository and run `npm install` to install all dependencies.
([Node](https://nodejs.org/en/) and [npm](https://www.npmjs.com) are required.)
## Commands
A few useful commands are configured in npm:
```
# Start the development server
npm start
# If the development server does not detect file changes, try starting as root
sudo npm start
# Lint your code
npm run lint
# Lint and fix errors if possible
npm run lint-fix
# Build your project
npm run build
```
## Configuration
In many situations, development and production environments require different
configurations. With
[Webpack Resolve](https://webpack.js.org/configuration/resolve/), this can be
handled easily. There are two configuration files, `config.js` and
`config.prod.js`, which you can adjust to your needs.
In your code, `require('config')` or `import * as config from 'config'`,
which will automatically resolve to `config.js` when using the development
server and to `config.prod.js` when building your project.
## Continuous Integration
The existing `.gitlab-ci.yml` configuration file contains three stages:
- **test**: Run tests, currently only eslint -- add your own if needed!
- **build**: Build the docker container and push it to the
[Docker Hub](hub.docker.com)
- **deploy**: Trigger a service update in the AMIV Cluster.
You can add your own tests to the **test** stage, but should not change the
**build** or **deploy** stages.
To enable building and deploying, a few steps are required:
### Configure a runner
You need to enable a runner for your project, which will work on CI jobs.
Under `Settings > CI/CD > Runners`, activate the AMIV Runner and you are
good to go.
### Configure build
Under `Settings > CI/CD > Secret Variables`, add the variable
`CI_REGISTRY_IMAGE` and set it to the appropriate repository on Docker Hub.
The account for AMIV images is called `amiveth`, therefore you should
use the following repository for your project: `amiveth/yourprojectname`.
The login credentials for the amiveth repository are saved in the AMIV
group on gitlab, you only need so set the name in your repository.
### Configure deploy
Before you can automatically update services, you need to manually
create them in the AMIV cluster. Contact the head of AMIV IT for this.
Afterwards, under `Settings > CI/CD > Secret Variables`, add the variable
`CI_DEPLOY_SERVICE` and set it to the name of your service in the AMIV
cluster.
## Acknowledgments
Many thanks go to Moritz Schneider, who created the initial
configuration for webpack!
// Development Configuration
export const greeting = 'Hi';
export const name = 'Developer';
// AMIV API and OAuth.
// The development API allows redirect to localhost for the client 'Local Tool'
// You do not need to change this
export const apiUrl = 'https://api-dev.amiv.ethz.ch';
export const OAuthId = 'Local Tool';
// Production Configuration
export const greeting = 'Hello';
export const name = 'Production';
// AMIV API and OAuth.
// You need to register a client id with the API, ask the head of IT for this
export const apiUrl = 'https://api.amiv.ethz.ch';
export const OAuthId = 'CHANGE THIS TO YOUR ID';
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>webpack-babel-eslint</title>
</head>
<body>
<script src="/dist/bundle.js"></script>
</body>
</html>
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /var/www/;
index index.html;
try_files $uri /index.html =404;
}
\ No newline at end of file
{
"name": "webpack-babel-eslint",
"version": "1.0.0",
"description": "A webpack boilerplate usable with any framework.",
"license": "MIT",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --hot --inline",
"build": "webpack -p --config webpack.config.prod.js",
"lint": "eslint src/**",
"lint-fix": "eslint --fix src/**"
},
"repository": {
"type": "git",
"url": "git@github.com:NotSpecial/webpack-babel-eslint.git"
},
"author": "Alexander Dietmüller",
"dependencies": {
"query-string": "^6.0.0"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-preset-env": "^1.6.1",
"compression-webpack-plugin": "^1.1.11",
"css-loader": "^0.28.11",
"eslint": "^4.19.1",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-import-resolver-webpack": "^0.9.0",
"eslint-loader": "^2.0.0",
"eslint-plugin-import": "^2.11.0",
"file-loader": "^1.1.11",
"style-loader": "^0.19.1",
"uglifyjs-webpack-plugin": "^1.2.5",
"webpack": "^3.11.0",
"webpack-dev-server": "^2.11.2"
}
}
// Go for it! :)
// Example for config usage, uses development/production config as needed
import { greeting, name } from 'config';
import { login, logout, getToken } from './oauth';
// OAuth automatically checks for a token, let's see if one was provided
// If there is a token, we are logged in!
const token = getToken();
const title = document.createElement('h1');
title.innerHTML = `${greeting}, ${name}`;
const main = document.createElement('p');
main.innerHTML = `You are${token ? ' ' : ' not '}logged in!`;
// Create a button for either login or logout (reload needed to see changes)
const button = document.createElement('button');
function logoutAndReload() {
logout();
window.location.reload();
}
button.addEventListener('click', token ? logoutAndReload : login);
button.innerHTML = token ? 'Logout' : 'Login';
document.body.appendChild(title);
document.body.appendChild(main);
document.body.appendChild(button);
/* Reference javascript client for simple AMIVAPI Oauth
More info on OAuth:
https://github.com/amiv-eth/amivapi/blob/master/docs/OAuth.md
See `index.js` for a usage example.
Note:
By simply editing the URL, the user can provide any token, not just required
ones. If you only use this token to send requests to the API, this is no
problem, since the API will reject invalid tokens.
*/
import queryString from 'query-string';
import { apiUrl, OAuthId } from 'config';
const ls = window.localStorage;
// Persist token and state for oauth-request
const session = {
token: ls.getItem('OAuth-Token'),
state: ls.getItem('OAuth-State'),
};
export function getToken() {
return session.token;
}
export function logout() {
session.token = '';
session.state = '';
ls.setItem('OAuth-Token', '');
ls.setItem('OAuth-State', '');
}
// Redirect to OAuth landing page
// As uri for the redirect back, use the current location
export function login() {
// Clear current session and save a random string for csrf protection
logout();
const state = Math.random().toString();
ls.setItem('OAuth-State', state);
const query = queryString.stringify({
response_type: 'token',
client_id: OAuthId,
redirect_uri: window.location.origin,
state,
});
// Redirect to AMIV api oauth page
window.location.href = `${apiUrl}/oauth?${query}`;
}
// Extract token from query string automatically if state matches
const params = queryString.parse(window.location.search);
if (params.state && params.access_token && (params.state === session.state)) {
session.token = params.access_token;
ls.setItem('OAuth-Token', session.token);
}
const publicPath = '/dist';
const config = {
context: `${__dirname}/src`, // `__dirname` is root of project
entry: './index.js',
output: {
path: `${__dirname}/dist`, // `dist` is the destination
filename: 'bundle.js',
},
// To run development server
devServer: {
contentBase: __dirname,
publicPath,
compress: true,
port: 9000,
hot: true,
index: 'index.html',
},
module: {
rules: [
{
test: /\.js$/,
enforce: 'pre',
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
emitWarning: true, // don't fail the build for linting errors
},
},
{
test: /\.js$/, // Check for all js files
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
options: { presets: ['env'] },
}],
},
{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
loader: 'file-loader',
options: {
useRelativePath: true,
publicPath,
},
},
],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
resolve: {
alias: {
config: `${__dirname}/config.js`,
},
},
devtool: 'eval-source-map', // Default development sourcemap
};
module.exports = config;
const webpack = require('webpack');
const CompressionPlugin = require('compression-webpack-plugin');
// Start with dev config
const config = require('./webpack.config.js');
// Remove development server and code map
config.devServer = undefined;
config.devtool = '';
// Add optimization plugins
config.plugins = [
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.AggressiveMergingPlugin(),
new CompressionPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8,
}),
];
// Replace development with production config
config.resolve.alias.config = `${__dirname}/config.prod.js`;
module.exports = config;
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment