Implement new Yarn/Gulp static asset build process (#446)

* First attempt at new build process
* Complete!
This commit is contained in:
Buster "Silver Eagle" Neece 2018-02-24 03:08:54 -06:00 committed by GitHub
parent e546d89475
commit 6d7fcfaadb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2437 additions and 882 deletions

10
.gitignore vendored
View File

@ -1,11 +1,5 @@
# Environment-specific files.
app/config/db.conf.php
app/config/apis.conf.php
app/config/influx.conf.php
app/config/cache.conf.php
# Local development files.
app/modules/frontend/controllers/UtilController.php
# Node Modules
node_modules
# Junk/cache files.
*Thumbs.db

View File

@ -78,7 +78,7 @@ return [
'sri' => 'sha256-LlN0a0J3hMkDLO1mhcMwy+GIMbIRV7kvKHx4oCxNoxI=',
],
[
'src' => 'js/app.min.js',
'src' => 'dist/app.min.js',
],
],
],
@ -133,7 +133,7 @@ return [
'files' => [
'css' => [
[
'src' => 'css/dark.css',
'src' => 'dist/dark.css',
],
],
]
@ -145,7 +145,7 @@ return [
'files' => [
'css' => [
[
'src' => 'css/light.css',
'src' => 'dist/light.css',
],
],
]
@ -166,7 +166,7 @@ return [
],
'js' => [
[
'src' => 'js/bootgrid/jquery.bootgrid.updated.min.js',
'src' => 'js/bootgrid/jquery.bootgrid.updated.js',
],
],
],

View File

@ -31,7 +31,7 @@ services:
build:
context: ./util/docker/static
volumes:
- ./web/static:/src
- ./web/static:/data
stations_cli:
image: azuracast/azuracast_stations:latest

View File

@ -1,18 +1,21 @@
FROM library/node
FROM library/node:8-alpine
# Install Bower & Grunt
RUN npm install -g bower grunt grunt-cli && \
echo '{ "allow_root": true }' > /root/.bowerrc
RUN apk update \
&& apk add bash
RUN mkdir -p /data \
&& chown -R node:node /data
RUN yarn global add gulp
COPY build_entrypoint.sh /
RUN chmod a+x /build_entrypoint.sh
# Define working directory.
WORKDIR /data
COPY build_entrypoint.sh /data
COPY package.json /data
RUN npm install --loglevel warn
RUN chmod a+x build_entrypoint.sh
# Define working user.
USER node
# Define default command.
CMD ["/data/build_entrypoint.sh"]
CMD ["/build_entrypoint.sh"]

View File

@ -1,14 +1,5 @@
#!/usr/bin/env bash
cd /data
ln -s /src/gruntfile.js /data/gruntfile.js
ln -s /src/assets.json /data/assets.json
ln -s /src/css /data/css
ln -s /src/js /data/js
ln -s /src/less /data/less
ln -s /src/vendors /data/vendors
ln -s /src/bower_components /data/bower_components
ln -s /src/bower.json /data/bower.json
yarn install
bash

View File

@ -1,15 +0,0 @@
{
"name": "superflat-admin",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.5",
"grunt-cache-bust": "^1.5.1",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-jshint": "~0.10.0",
"grunt-contrib-less": "~1.3.0",
"grunt-contrib-nodeunit": "~0.4.1",
"grunt-contrib-uglify": "^0.8.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-csssplit": "^0.4.0"
}
}

View File

@ -1 +1,5 @@
{"js/radio.js":"js/radio.js?2c18564955716845","js/nchan.js":"js/nchan.js?c512cda73ce7b123","js/app.min.js":"js/app.min.js?0272cff3887c5a7c","js/app.js":"js/app.js?04699c2d5e572265","css/light.css":"css/light.css?5e71099ff8041fd4","css/dark.css":"css/dark.css?657447d00ba144f4"}
{
"dist/app.min.js": "dist/app-a77786a67b.min.js",
"dist/dark.css": "dist/dark-35a680566c.css",
"dist/light.css": "dist/light-c26f7d47d1.css"
}

View File

@ -1,19 +0,0 @@
{
"name": "vendors",
"version": "0.0.0",
"authors": [],
"description": "",
"main": "",
"moduleType": [],
"license": "MIT",
"homepage": "",
"ignore": [
"**/.*",
"node_modules",
"bower_components"
],
"dependencies": {
"bootstrap": "^3.3.7",
"material-shadows": "~2.0.1"
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
web/static/dist/app-a77786a67b.min.js vendored Normal file

File diff suppressed because one or more lines are too long

6
web/static/dist/dark-35a680566c.css vendored Normal file

File diff suppressed because one or more lines are too long

6
web/static/dist/light-c26f7d47d1.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,91 +0,0 @@
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
less: {
development: {
options: {
paths: ["css"],
compress: true,
sourceMap: true,
sourceMapRootpath: '/static',
sourceMapBasepath: function (f) {
this.sourceMapURL = this.sourceMapFilename.substr(this.sourceMapFilename.lastIndexOf('/') + 1);
return "wwwroot/";
}
},
files: {
"css/light.css": "less/light.less",
"css/dark.css": "less/dark.less"
},
cleancss: true
}
},
concat: {
dist: {
src: ['js/inc/**/*.js'],
dest: 'js/app.js'
}
},
uglify: {
options: {
mangle: false
},
my_target: {
files: {
'js/app.min.js': 'js/app.js',
'js/bootgrid/jquery.bootgrid.updated.min.js': 'js/bootgrid/jquery.bootgrid.updated.js'
}
}
},
csssplit: {
your_target: {
src: ['css/app.css'],
dest: 'css/app.min.css',
options: {
maxSelectors: 4095,
suffix: '.'
}
}
},
watch: {
less: {
files: ['less/**/*.less'], // which files to watch
tasks: ['less'],
options: {
nospawn: true,
livereload: 8122
}
},
js: {
files: ['js/inc/**/*.js'], // which files to watch
tasks: ['concat', 'uglify']
}
},
cacheBust: {
core: {
options: {
assets: ['js/*.js', 'css/*.css'],
queryString: true,
jsonOutput: true,
jsonOutputFilename: 'assets.json'
},
src: ['index.html']
}
}
});
// Load the plugin that provides the "less" task.
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-csssplit');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-cache-bust');
// Default task(s).
grunt.registerTask('default', ['less', 'concat', 'uglify', 'cacheBust']);
grunt.registerTask('js', ['concat', 'uglify']);
};

43
web/static/gulpfile.js Normal file
View File

@ -0,0 +1,43 @@
'use strict';
const gulp = require('gulp');
const clean = require('gulp-clean');
const rev = require('gulp-rev');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
const sourcemaps = require('gulp-sourcemaps');
const less = require('gulp-less');
const clean_css = require('gulp-clean-css');
var revdel = require('gulp-rev-delete-original');
gulp.task('clean', function() {
return gulp.src(['./dist/**/*', './assets.json'], { read: false })
.pipe(clean());
});
gulp.task('build-js', ['clean'], function() {
return gulp.src('./js/inc/*.js')
.pipe(sourcemaps.init())
.pipe(concat('app.min.js'))
.pipe(uglify())
.pipe(sourcemaps.write())
.pipe(gulp.dest('./dist'));
});
gulp.task('build-css', ['clean'], function() {
return gulp.src(['./less/light.less', './less/dark.less'])
.pipe(sourcemaps.init())
.pipe(less())
.pipe(clean_css())
.pipe(sourcemaps.write())
.pipe(gulp.dest('./dist'));
});
gulp.task('default', ['build-js', 'build-css'], function() {
return gulp.src(['./dist/*'], { base: '.' })
.pipe(rev())
.pipe(revdel())
.pipe(gulp.dest('.'))
.pipe(rev.manifest('assets.json'))
.pipe(gulp.dest('./'));
});

View File

@ -1,709 +0,0 @@
$(document).ready(function () {
$('body').on('click', '[data-ma-action]', function (e) {
e.preventDefault();
var $this = $(this);
var action = $(this).data('ma-action');
switch (action) {
/*-------------------------------------------
Sidebar & Chat Open/Close
---------------------------------------------*/
case 'sidebar-open':
var target = $this.data('ma-target');
var backdrop = '<div data-ma-action="sidebar-close" class="ma-backdrop" />';
$('body').addClass('sidebar-toggled');
$('#header, #header-alt, #main').append(backdrop);
$this.addClass('toggled');
$(target).addClass('toggled');
break;
case 'sidebar-close':
$('body').removeClass('sidebar-toggled');
$('.ma-backdrop').remove();
$('.sidebar, .ma-trigger').removeClass('toggled')
break;
/*-------------------------------------------
Mainmenu Submenu Toggle
---------------------------------------------*/
case 'submenu-toggle':
$this.next().slideToggle(200);
$this.parent().toggleClass('toggled');
break;
/*-------------------------------------------
Top Search Open/Close
---------------------------------------------*/
//Open
case 'search-open':
$('#header').addClass('search-toggled');
$('#top-search-wrap input').focus();
break;
//Close
case 'search-close':
$('#header').removeClass('search-toggled');
break;
/*-------------------------------------------
Header Notification Clear
---------------------------------------------*/
case 'clear-notification':
var x = $this.closest('.list-group');
var y = x.find('.list-group-item');
var z = y.size();
$this.parent().fadeOut();
x.find('.list-group').prepend('<i class="grid-loading hide-it"></i>');
x.find('.grid-loading').fadeIn(1500);
var w = 0;
y.each(function(){
var z = $(this);
setTimeout(function(){
z.addClass('animated fadeOutRightBig').delay(1000).queue(function(){
z.remove();
});
}, w+=150);
})
//Popup empty message
setTimeout(function(){
$('#notifications').addClass('empty');
}, (z*150)+200);
break;
/*-------------------------------------------
Fullscreen Browsing
---------------------------------------------*/
case 'fullscreen':
//Launch
function launchIntoFullscreen(element) {
if(element.requestFullscreen) {
element.requestFullscreen();
} else if(element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if(element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
} else if(element.msRequestFullscreen) {
element.msRequestFullscreen();
}
}
//Exit
function exitFullscreen() {
if(document.exitFullscreen) {
document.exitFullscreen();
} else if(document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if(document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
}
launchIntoFullscreen(document.documentElement);
break;
/*-------------------------------------------
Clear Local Storage
---------------------------------------------*/
case 'clear-localstorage':
swal({
title: "Are you sure?",
text: "All your saved localStorage values will be removed",
type: "warning",
showCancelButton: true,
confirmButtonText: "Yes, delete it!",
closeOnConfirm: false
}, function(){
localStorage.clear();
swal("Done!", "localStorage is cleared", "success");
});
break;
/*-------------------------------------------
Print
---------------------------------------------*/
case 'print':
window.print();
break;
/*-------------------------------------------
Login Window Switch
---------------------------------------------*/
case 'login-switch':
var loginblock = $this.data('ma-block');
var loginParent = $this.closest('.lc-block');
loginParent.removeClass('toggled');
setTimeout(function(){
$(loginblock).addClass('toggled');
});
break;
/*-------------------------------------------
Profile Edit/Edit Cancel
---------------------------------------------*/
//Edit
case 'profile-edit':
$this.closest('.pmb-block').toggleClass('toggled');
break;
case 'profile-edit-cancel':
$(this).closest('.pmb-block').removeClass('toggled');
break;
/*-------------------------------------------
Action Header Open/Close
---------------------------------------------*/
//Open
case 'action-header-open':
ahParent = $this.closest('.action-header').find('.ah-search');
ahParent.fadeIn(300);
ahParent.find('.ahs-input').focus();
break;
//Close
case 'action-header-close':
ahParent.fadeOut(300);
setTimeout(function(){
ahParent.find('.ahs-input').val('');
}, 350);
break;
/*-------------------------------------------
Wall Comment Open/Close
---------------------------------------------*/
//Open
case 'wall-comment-open':
if(!($this).closest('.wic-form').hasClass('toggled')) {
$this.closest('.wic-form').addClass('toggled');
}
break;
//Close
case 'wall-comment-close':
$this.closest('.wic-form').find('textarea').val('');
$this.closest('.wic-form').removeClass('toggled');
break;
/*-------------------------------------------
Todo Form Open/Close
---------------------------------------------*/
//Open
case 'todo-form-open':
$this.closest('.t-add').addClass('toggled');
break;
//Close
case 'todo-form-close':
$this.closest('.t-add').removeClass('toggled');
$this.closest('.t-add').find('textarea').val('');
break;
}
});
});
$(function() {
$('a.btn-danger').on('click', function(e) {
e.preventDefault();
var linkUrl = $(this).attr('href');
swal({
title: 'Are you sure?',
type: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Yes',
closeOnConfirm: false,
showLoaderOnConfirm: true
}, function() {
window.location.href = linkUrl;
});
return false;
});
});
$(function() {
$('form.form').each(function() {
var $form = $(this);
$form.addClass('fa-form-engine fa-form');
$form.find('.form-group > label').addClass('control-label');
$form.find('input:not(input[type=button],input[type=submit],input[type=reset],input[type=radio],input[type=checkbox]),textarea,select').addClass('form-control');
$form.find('select').wrap('<div class="select" />');
autosize($form.find('textarea'));
$form.find('input[type=radio]').each(function() {
$(this).closest('.form-field').addClass('radio-group');
$(this).next('label').addBack().wrapAll('<div class="radio m-b-15" />');
});
$form.find('input[type=checkbox]').each(function() {
$(this).closest('.form-field').addClass('checkbox-group');
$(this).next('label').addBack().wrapAll('<div class="checkbox m-b-15" />');
});
$form.find('input[type=checkbox],input[type=radio]').after('<i class="input-helper"></i>');
$form.find('input[type=checkbox].inline').removeClass('inline').closest('div.checkbox').addClass('checkbox-inline');
$form.find('input[type=radio].inline').removeClass('inline').closest('div.radio').addClass('radio-inline');
$form.find('div.checkbox:not(.checkbox-inline)').addClass('m-b-15');
$form.find('div.radio:not(.radio-inline)').addClass('m-b-15');
$form.find('.help-block.form-error').parent().addClass('has-error');
$form.find('.help-block.form-success').parent().addClass('has-success');
$form.find('.help-block.form-warning').parent().addClass('has-warning');
$form.find('input[type=button],input[type=submit],input[type=reset]').addClass('btn m-t-10');
});
});
/*----------------------------------------------------------
Detect Mobile Browser
-----------------------------------------------------------*/
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
$('html').addClass('ismobile');
}
$(document).ready(function () {
/*----------------------------------------------------------
Scrollbar
-----------------------------------------------------------*/
function scrollBar(selector, theme, mousewheelaxis) {
$(selector).mCustomScrollbar({
theme: theme,
scrollInertia: 100,
axis: 'mousewheelaxis',
mouseWheel: {
enable: true,
axis: mousewheelaxis,
preventDefault: true
}
});
}
if (!$('html').hasClass('ismobile')) {
//On Custom Class
if ($('.c-overflow')[0]) {
scrollBar('.c-overflow', 'minimal-dark', 'y');
}
}
/*----------------------------------------------------------
Dropdown Menu
-----------------------------------------------------------*/
if ($('.dropdown')[0]) {
//Propagate
$('body').on('click', '.dropdown.open .dropdown-menu', function (e) {
e.stopPropagation();
});
$('.dropdown').on('shown.bs.dropdown', function (e) {
if ($(this).attr('data-animation')) {
$animArray = [];
$animation = $(this).data('animation');
$animArray = $animation.split(',');
$animationIn = 'animated ' + $animArray[0];
$animationOut = 'animated ' + $animArray[1];
$animationDuration = ''
if (!$animArray[2]) {
$animationDuration = 500; //if duration is not defined, default is set to 500ms
}
else {
$animationDuration = $animArray[2];
}
$(this).find('.dropdown-menu').removeClass($animationOut)
$(this).find('.dropdown-menu').addClass($animationIn);
}
});
$('.dropdown').on('hide.bs.dropdown', function (e) {
if ($(this).attr('data-animation')) {
e.preventDefault();
$this = $(this);
$dropdownMenu = $this.find('.dropdown-menu');
$dropdownMenu.addClass($animationOut);
setTimeout(function () {
$this.removeClass('open')
}, $animationDuration);
}
});
}
/*----------------------------------------------------------
Auto Size Textare
-----------------------------------------------------------*/
if ($('.auto-size')[0]) {
autosize($('.auto-size'));
}
/*----------------------------------------------------------
Text Field
-----------------------------------------------------------*/
//Add blue animated border and remove with condition when focus and blur
if ($('.fg-line')[0]) {
$('body').on('focus', '.fg-line .form-control', function () {
$(this).closest('.fg-line').addClass('fg-toggled');
})
$('body').on('blur', '.form-control', function () {
var p = $(this).closest('.form-group, .input-group');
var i = p.find('.form-control').val();
if (p.hasClass('fg-float')) {
if (i.length == 0) {
$(this).closest('.fg-line').removeClass('fg-toggled');
}
}
else {
$(this).closest('.fg-line').removeClass('fg-toggled');
}
});
}
//Add blue border for pre-valued fg-flot text feilds
if ($('.fg-float')[0]) {
$('.fg-float .form-control').each(function () {
var i = $(this).val();
if (!i.length == 0) {
$(this).closest('.fg-line').addClass('fg-toggled');
}
});
}
/*----------------------------------------------------------
NoUiSlider (Input Slider)
-----------------------------------------------------------*/
//Basic
if ($('#input-slider')[0]) {
var slider = document.getElementById('input-slider');
noUiSlider.create(slider, {
start: [20],
connect: 'lower',
range: {
'min': 0,
'max': 100
}
});
}
//Range
if ($('#input-slider-range')[0]) {
var sliderRange = document.getElementById('input-slider-range');
noUiSlider.create(sliderRange, {
start: [40, 70],
connect: true,
range: {
'min': 0,
'max': 100
}
});
}
//Range with value
if ($('#input-slider-value')[0]) {
var sliderRangeValue = document.getElementById('input-slider-value');
noUiSlider.create(sliderRangeValue, {
start: [10, 50],
connect: true,
range: {
'min': 0,
'max': 100
}
});
sliderRangeValue.noUiSlider.on('update', function (values, handle) {
document.getElementById('input-slider-value-output').innerHTML = values[handle];
});
}
/*----------------------------------------------------------
Input Mask
-----------------------------------------------------------*/
if ($('input-mask')[0]) {
$('.input-mask').mask();
}
/*-----------------------------------------------------------
Summernote HTML Editor
-----------------------------------------------------------*/
if ($('.html-editor')[0]) {
$('.html-editor').summernote({
height: 150
});
}
if ($('.html-editor-click')[0]) {
//Edit
$('body').on('click', '.hec-button', function () {
$('.html-editor-click').summernote({
focus: true
});
$('.hec-save').show();
})
//Save
$('body').on('click', '.hec-save', function () {
$('.html-editor-click').code();
$('.html-editor-click').destroy();
$('.hec-save').hide();
});
}
//Air Mode
if ($('.html-editor-airmod')[0]) {
$('.html-editor-airmod').summernote({
airMode: true
});
}
/*-----------------------------------------------------------
Date Time Picker
-----------------------------------------------------------*/
//Date Time Picker
if ($('.date-time-picker')[0]) {
$('.date-time-picker').datetimepicker();
}
//Time
if ($('.time-picker')[0]) {
$('.time-picker').datetimepicker({
format: 'LT'
});
}
//Date
if ($('.date-picker')[0]) {
$('.date-picker').datetimepicker({
format: 'DD/MM/YYYY'
});
}
$('.date-picker').on('dp.hide', function () {
$(this).closest('.dtp-container').removeClass('fg-toggled');
$(this).blur();
})
/*-----------------------------------------------------------
Waves
-----------------------------------------------------------
(function(){
Waves.attach('.btn:not(.btn-icon):not(.btn-float)');
Waves.attach('.btn-icon, .btn-float', ['waves-circle', 'waves-float']);
Waves.init();
})();
*/
/*----------------------------------------------------------
Lightbox
-----------------------------------------------------------*/
if ($('.lightbox')[0]) {
$('.lightbox').lightGallery({
enableTouch: true
});
}
/*-----------------------------------------------------------
Link prevent
-----------------------------------------------------------*/
$('body').on('click', '.a-prevent', function (e) {
e.preventDefault();
});
/*----------------------------------------------------------
Bootstrap Accordion Fix
-----------------------------------------------------------*/
if ($('.collapse')[0]) {
//Add active class for opened items
$('.collapse').on('show.bs.collapse', function (e) {
$(this).closest('.panel').find('.panel-heading').addClass('active');
});
$('.collapse').on('hide.bs.collapse', function (e) {
$(this).closest('.panel').find('.panel-heading').removeClass('active');
});
//Add active class for pre opened items
$('.collapse.in').each(function () {
$(this).closest('.panel').find('.panel-heading').addClass('active');
});
}
/*-----------------------------------------------------------
Tooltips
-----------------------------------------------------------*/
if ($('[data-toggle="tooltip"]')[0]) {
$('[data-toggle="tooltip"]').tooltip();
}
/*-----------------------------------------------------------
Popover
-----------------------------------------------------------*/
if ($('[data-toggle="popover"]')[0]) {
$('[data-toggle="popover"]').popover();
}
/*-----------------------------------------------------------
IE 9 Placeholder
-----------------------------------------------------------*/
if ($('html').hasClass('ie9')) {
$('input, textarea').placeholder({
customClass: 'ie9-placeholder'
});
}
});
function notify(message, type, minimal_layout) {
var growlSettings = {
type: type,
allow_dismiss: true,
label: 'Cancel',
className: 'btn-xs btn-inverse align-right',
placement: {
from: 'top',
align: 'right'
},
delay: 10000,
animate: {
enter: 'animated fadeIn',
exit: 'animated fadeOut'
},
offset: {
x: 20,
y: 85
}
};
if (minimal_layout) {
growlSettings.placement.from = 'top';
growlSettings.placement.align = 'center';
growlSettings.offset.y = 20;
}
$.notify({ message: message }, growlSettings);
}
$(document).ready(function () {
// Show password strength meter.
if (typeof zxcvbn === 'function') {
$('input[type=password].strength').on('keyup', function(e) {
var result = zxcvbn($(this).val()),
score = result.score;
var group = $(this).closest('.form-group');
if (!group.length) {
group = $(this).closest('div');
}
var explanation = group.find('.help-block.password-explanation');
if (!explanation.length) {
explanation = $('<small class="help-block password-explanation" />');
var label = group.find('label');
if (label.length) {
label.after(explanation);
} else {
$(this).after(explanation);
}
explanation = group.find('.help-block.password-explanation');
}
if (result.feedback.warning) {
explanation.text(result.feedback.warning).show();
} else {
explanation.hide();
}
group.removeClass('has-success has-warning has-error');
switch (score) {
case 0:
case 1:
group.addClass('has-error');
break;
case 2:
case 3:
group.addClass('has-warning');
break;
case 4:
group.addClass('has-success');
break;
}
});
}
});

File diff suppressed because one or more lines are too long

15
web/static/package.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "AzuraCast",
"license": "Apache-2.0",
"dependencies": {
"gulp": "^3.9.1",
"gulp-clean": "^0.4.0",
"gulp-clean-css": "^3.9.2",
"gulp-concat": "^2.6.1",
"gulp-less": "^4.0.0",
"gulp-rev": "^8.1.1",
"gulp-rev-delete-original": "^0.2.3",
"gulp-sourcemaps": "^2.6.4",
"gulp-uglify": "^3.0.0"
}
}

2338
web/static/yarn.lock Normal file

File diff suppressed because it is too large Load Diff