Add assets

This commit is contained in:
Alice Gaudon 2020-04-23 18:07:39 +02:00
parent f59939daff
commit 167f1d3366
16 changed files with 944 additions and 3 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
node_modules
.idea
public
dist

10
assets/config.json Normal file
View File

@ -0,0 +1,10 @@
{
"bundles": {
"app": "js/app.js",
"layout": "sass/layout.scss",
"error": "sass/error.scss",
"logo": "img/logo.svg",
"logo_png": "img/logox128.png",
"logo_png_xxl": "img/logox1024.png"
}
}

71
assets/img/logo.svg Normal file
View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
version="1.1"
id="svg6"
sodipodi:docname="logo.svg"
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
inkscape:export-filename="/r/arisu/dev/streams/wms/assets/img/logox128.png"
inkscape:export-xdpi="512"
inkscape:export-ydpi="512">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1381"
id="namedview8"
showgrid="false"
inkscape:zoom="45.254834"
inkscape:cx="9.0192696"
inkscape:cy="11.978294"
inkscape:window-x="1920"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="svg6">
<inkscape:grid
spacingx="0.5"
spacingy="0.5"
type="xygrid"
id="grid4542" />
</sodipodi:namedview>
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#00766c;fill-opacity:1;fill-rule:nonzero;stroke:#00766c;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 4.6020263,4.6020261 c -4.08077722,4.0820101 -4.08077722,10.7139369 0,14.7959479 m 0,0 0.6656889,-0.665689 c -3.7210992,-3.722224 -3.7210992,-9.7423466 0,-13.4645699 L 4.6020263,4.6020261 m 14.7959477,0 -0.665689,0.665689 c 3.721099,3.7222233 3.721099,9.7423459 0,13.4645699 l 0.665689,0.665689 m 0,0 c 4.080777,-4.082011 4.080777,-10.7139378 0,-14.7959479 M 8.0959735,15.904026 c -2.1644289,-2.162022 -2.1644289,-5.655225 0,-7.8172472 m 0,0 L 7.4302847,7.419251 c -2.5246945,2.5218873 -2.5246945,6.628577 0,9.150465 l 0.6656888,-0.66569 M 15.904026,8.0959736 c 2.164429,2.1620214 2.164429,5.6552244 0,7.8172474 m 0,0 0.66569,0.667527 c 2.524693,-2.521887 2.524693,-6.6285761 0,-9.1504633 l -0.66569,0.6656889"
id="path4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccccccc" />
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
assets/img/logox1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
assets/img/logox128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

6
assets/js/app.js Normal file
View File

@ -0,0 +1,6 @@
import './external_links';
import './message_icons';
import '../sass/app.scss';
console.log('Hello world!');

View File

@ -0,0 +1,9 @@
import feather from "feather-icons";
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('a[target="_blank"]').forEach(el => {
el.innerHTML += `<i data-feather="external-link"></i>`;
});
feather.replace();
});

View File

@ -0,0 +1,21 @@
import feather from "feather-icons";
document.addEventListener('DOMContentLoaded', () => {
const messageTypeToIcon = {
info: 'info',
success: 'check',
warning: 'alert-triangle',
error: 'x-circle',
question: 'help-circle',
};
document.querySelectorAll('.message').forEach(el => {
const type = el.dataset['type'];
const icon = el.querySelector('.icon');
const svgContainer = document.createElement('div');
svgContainer.innerHTML = feather.icons[messageTypeToIcon[type]].toSvg();
el.insertBefore(svgContainer.firstChild, icon);
icon.remove();
});
feather.replace();
});

81
assets/sass/_fonts.scss Normal file
View File

@ -0,0 +1,81 @@
/* vietnamese */
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 300;
font-display: swap;
src: local('Nunito Sans Light'), local('NunitoSans-Light'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8WAc5iU1EQVg.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 300;
font-display: swap;
src: local('Nunito Sans Light'), local('NunitoSans-Light'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8WAc5jU1EQVg.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 300;
font-display: swap;
src: local('Nunito Sans Light'), local('NunitoSans-Light'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8WAc5tU1E.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: local('Nunito Sans Regular'), local('NunitoSans-Regular'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe0qMImSLYBIv1o4X1M8cceyI9tScg.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: local('Nunito Sans Regular'), local('NunitoSans-Regular'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe0qMImSLYBIv1o4X1M8ccezI9tScg.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 400;
font-display: swap;
src: local('Nunito Sans Regular'), local('NunitoSans-Regular'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe0qMImSLYBIv1o4X1M8cce9I9s.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: local('Nunito Sans Bold'), local('NunitoSans-Bold'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8GBs5iU1EQVg.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: local('Nunito Sans Bold'), local('NunitoSans-Bold'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8GBs5jU1EQVg.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Nunito Sans';
font-style: normal;
font-weight: 700;
font-display: swap;
src: local('Nunito Sans Bold'), local('NunitoSans-Bold'), url(https://fonts.gstatic.com/s/nunitosans/v5/pe03MImSLYBIv1o4X1M8cc8GBs5tU1E.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

23
assets/sass/_vars.scss Normal file
View File

@ -0,0 +1,23 @@
$primary: #1e2932;
$primaryForeground: #f0f0f0;
$secondary: #00766c;
$secondaryForeground: $primaryForeground;
$backgroundColor: $primary;
$defaultTextColor: $primaryForeground;
$info: #49fb;
$infoText: darken($info, 42%);
$infoColor: desaturate($infoText, 50%);
$success: #5f5b;
$successText: darken($success, 45%);
$successColor: desaturate($successText, 50%);
$warning: #fc0b;
$warningText: darken($warning, 30%);
$warningColor: desaturate($warningText, 50%);
$error: #f00b;
$errorText: darken($error, 30%);
$errorColor: desaturate($errorText, 50%);

1
assets/sass/app.scss Normal file
View File

@ -0,0 +1 @@
@import "layout";

90
assets/sass/error.scss Normal file
View File

@ -0,0 +1,90 @@
@import "layout";
header, footer {
margin: 0;
padding: 0;
height: 0;
}
main {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.messages {
margin-bottom: 32px;
}
.error-code {
font-size: 36px;
}
.error-message {
font-size: 32px;
}
.error-instructions {
margin-top: 32px;
font-size: 20px;
}
nav {
margin-top: 32px;
}
&::before {
content: "Oops";
position: absolute;
z-index: -1;
font-size: #{'min(50vh, 40vw)'};
opacity: 0.025;
}
}
.contact {
text-align: center;
padding: 8px;
}
.logo {
position: absolute;
top: 0;
left: 0;
width: 100%;
margin-top: 24px;
text-align: center;
a {
position: relative;
padding: 16px;
color: $defaultTextColor;
&:hover {
color: #fff;
&::before {
opacity: 0.2;
}
}
&::before {
content: "";
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-image: url(../img/logo.svg);
background-repeat: no-repeat;
background-position: center;
background-size: 64px;
opacity: 0.075;
filter: contrast(0);
}
}
}

512
assets/sass/layout.scss Normal file
View File

@ -0,0 +1,512 @@
@import "vars";
@import 'fonts';
* {
box-sizing: border-box;
}
html, body {
height: 100%;
}
body {
display: flex;
flex-direction: column;
margin: 0;
font-family: "Nunito Sans", sans-serif;
font-size: 16px;
color: $defaultTextColor;
background-color: $backgroundColor;
}
header {
display: flex;
flex-direction: row;
justify-content: space-between;
$headerHeight: 64px;
height: $headerHeight;
line-height: $headerHeight;
$headerBackground: darken($primary, 1.75%);
background-color: $headerBackground;
.logo {
display: flex;
flex-direction: row;
padding: 0 24px 0 16px;
font-size: 32px;
color: $defaultTextColor;
&:hover {
color: lighten($defaultTextColor, 10%);
}
img {
width: $headerHeight;
height: $headerHeight;
margin-right: 16px;
}
}
nav ul {
display: flex;
flex-direction: row;
margin: 0;
padding: 0;
font-size: 20px;
li {
list-style: none;
a, span {
display: flex;
flex-direction: row;
align-items: center;
height: 64px;
padding: 0 24px;
.feather {
--icon-size: 24px;
margin-right: 10px;
}
}
a:hover {
background-color: #fff1;
}
}
}
}
footer {
padding: 8px;
margin-top: 8px;
text-align: center;
background-color: darken($primary, 3%);
}
main {
flex: 1;
padding: 8px;
}
h1 {
text-align: center;
font-size: 32px;
& + p {
text-align: center;
font-size: 20px;
}
}
h1, h2 {
font-weight: 100;
}
h3, h4 {
font-weight: 300;
}
section > h2, .panel > h2 {
display: flex;
flex-direction: row;
align-items: center;
position: relative;
text-align: center;
margin-top: 16px;
&::before, &::after {
content: "";
flex: 1;
margin: 0 32px;
height: 0;
border-bottom: 1px solid $defaultTextColor;
opacity: 0.2;
}
}
section > hr, .panel > hr {
border: 0;
border-bottom: 1px solid $defaultTextColor;
opacity: 0.2;
margin: 8px 32px;
}
a {
color: $secondary;
text-decoration: none;
&:hover {
color: lighten($secondary, 10%);
}
.feather.feather-external-link {
--icon-size: 16px;
margin-left: 4px;
margin-top: -3px;
}
}
form {
padding: 8px 16px;
text-align: center;
.form-field {
position: relative;
display: flex;
flex-direction: column;
margin: 16px auto;
label {
position: absolute;
left: 8px;
top: 20px;
user-select: none;
font-size: 16px;
opacity: 0.75;
transition-property: top, font-size;
transition-duration: 150ms;
transition-timing-function: ease-out;
cursor: text;
}
input, select, .input-group {
border: 0;
border-bottom: 2px solid #0008;
color: $defaultTextColor;
background: rgba(255, 255, 255, 0.05);
border-radius: 3px 3px 0 0;
font-size: 16px;
&:focus, &:not([value=""]) {
~ label {
top: 8px;
font-size: 14px;
}
}
}
input, select, .form-display {
display: block;
padding: 32px 8px 8px 8px;
width: 100%;
}
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
&::-ms-expand {
display: none;
}
& + .feather {
position: absolute;
z-index: -1;
right: 8px;
bottom: 8px;
transition: transform 150ms ease-out;
}
// Temporary
&:focus + .feather {
transform: rotateX(180deg);
}
}
input[type=color] {
height: calc(32px + 8px + 32px);
}
&.inline {
flex-direction: row;
input[type=checkbox] {
text-align: left;
width: min-content;
height: min-content;
& ~ label {
position: static;
display: inline;
padding-left: 8px;
font-size: 16px;
}
}
}
.input-group {
display: flex;
flex-shrink: 1;
flex-direction: row;
div {
position: relative;
flex: 1;
input {
width: 100%;
margin-top: 24px;
padding-top: 8px;
border: 0;
background: transparent;
}
> input + * {
position: absolute;
top: 32px;
right: 28px;
user-select: none;
text-align: right;
}
}
}
.error, .hint {
padding: 2px;
text-align: left;
font-size: 14px;
.feather {
--icon-size: 14px;
}
}
.error {
color: $error;
}
}
}
button, .button {
display: inline-flex;
margin: 8px;
padding: 12px 16px;
border: 0;
border-radius: 5px;
cursor: pointer;
text-transform: uppercase;
font-size: 16px;
font-weight: bolder;
line-height: 16px;
.feather {
--icon-size: 16px;
margin-right: 8px;
}
&, &.primary {
color: $primaryForeground;
background-color: $secondary;
&:hover {
background-color: lighten($secondary, 10%);
}
}
&.info {
background-color: $infoColor;
}
&.success {
background-color: $successColor;
}
&.warning {
background-color: $warningColor;
}
&.error, &.danger {
background-color: $errorColor;
&:hover {
background-color: lighten($errorColor, 10%);
}
}
&.transparent {
background-color: transparent;
}
&:hover {
color: $primaryForeground;
}
}
.data-table {
width: 100%;
text-align: left;
border-collapse: collapse;
th, td {
padding: 8px;
}
th {
border-bottom: 1px solid #ffffff17;
}
tr:nth-child(even) {
background-color: #ffffff08;
}
tr:hover {
background-color: #ffffff18;
}
thead tr:hover {
background-color: transparent;
}
}
// ---
// --- Layout helpers
// ---
.center {
text-align: center;
}
.container {
padding: 0 16px;
max-width: 632px;
margin: 0 auto;
}
.panel {
margin: 16px 0;
padding: 8px;
border: 1px solid rgba(0, 0, 0, 0.1);
background-color: rgba(255, 255, 255, 0.03);
border-radius: 5px;
p {
margin: 16px 8px;
}
}
.sub-panel {
margin: 32px -18px;
padding: 1px 16px;
border: 2px solid rgba(255, 255, 255, 0.05);
border-radius: 5px;
input, select, .input-group {
border-radius: 5px !important;
border-width: 0 !important;
}
}
// ---
// --- Feather
// ---
.feather {
flex-shrink: 0;
--icon-size: 24px;
width: var(--icon-size);
height: var(--icon-size);
stroke: currentColor;
stroke-width: 2;
stroke-linecap: square;
stroke-linejoin: miter;
fill: none;
vertical-align: middle;
}
// ---
// --- Helper classes
// ---
.message {
display: flex;
flex-direction: row;
align-items: center;
padding: 8px 16px;
border-radius: 5px;
.feather {
--icon-size: 24px;
margin-right: 8px;
}
&:not(&-discreet) {
background-color: #fff5;
&[data-type=info], &[data-type=question] {
background-color: $infoColor;
}
&[data-type=success] {
background-color: $successColor;
}
&[data-type=warning] {
background-color: $warningColor;
}
&[data-type=error] {
background-color: $errorColor;
}
}
&-discreet {
opacity: 0.75;
.feather {
--icon-size: 20px;
}
}
}
.messages .message:not(:last-child) {
margin-bottom: 8px;
}
.container > .messages:first-child {
margin-top: 16px;
}
.copyable-text {
display: flex;
flex-direction: row;
margin: 8px;
background-color: darken($backgroundColor, 2%);
border-radius: 5px;
overflow: hidden;
.title {
padding: 8px;
}
.content {
overflow: hidden;
white-space: nowrap;
padding: 8px;
}
.copy-button {
margin: 0;
padding: 0;
border-radius: 0;
.feather {
--icon-size: 20px;
margin: 8px;
}
}
}

View File

@ -2,19 +2,48 @@
"name": "aldap",
"version": "0.1.0",
"description": "Authentication LDAP server",
"main": "index.js",
"repository": "git@gitlab.com:ArisuOngaku/aldap.git",
"author": "Alice Gaudon <alice@gaudon.pro>",
"license": "MIT",
"private": true,
"main": "dist/main.js",
"scripts": {
"test": "jest --verbose --runInBand",
"dist-webpack": "webpack --mode production",
"dist": "tsc && npm run dist-webpack",
"dev": "concurrently -k -n \"Typescript,Node,Webpack,Maildev\" -p \"[{name}]\" -c \"blue,green,red,yellow\" \"tsc --watch\" \"nodemon dist/main.js\" \"webpack --watch --mode development\" \"maildev\"",
"start": "yarn dist && node dist/main.js"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"@types/config": "^0.0.36",
"@types/express": "^4.17.6",
"@types/node": "^13.13.2",
"babel-loader": "^8.1.0",
"concurrently": "^5.1.0",
"css-loader": "^3.5.2",
"feather-icons": "^4.28.0",
"file-loader": "^6.0.0",
"imagemin": "^7.0.1",
"imagemin-gifsicle": "^7.0.0",
"imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^8.0.0",
"imagemin-svgo": "^7.1.0",
"img-loader": "^3.0.1",
"jest": "^25.4.0",
"mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.14.0",
"nodemon": "^2.0.3",
"sass-loader": "^8.0.2",
"ts-jest": "^25.4.0",
"typescript": "^3.8.3",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"wms-core": "^0.2.0"
},
"dependencies": {
"config": "^3.3.1"
"config": "^3.3.1",
"express": "^4.17.1"
}
}

0
public/.gitkeep Normal file
View File

86
webpack.config.js Normal file
View File

@ -0,0 +1,86 @@
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const dev = process.env.NODE_ENV === 'development';
const userConfig = require('./assets/config.json');
for (const b in userConfig.bundles) {
if (userConfig.bundles.hasOwnProperty(b)) {
userConfig.bundles[b] = `./assets/${userConfig.bundles[b]}`;
}
}
const config = {
entry: userConfig.bundles,
output: {
path: path.resolve(__dirname, 'public/js'),
filename: '[name].js'
},
devtool: dev ? 'eval-source-map' : undefined,
module: {
rules: [
{
test: /\.js$/i,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
}
}
]
},
{
test: /\.s[ac]ss$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '/',
}
},
'css-loader',
'sass-loader',
]
},
{
test: /\.(woff2?|eot|ttf|otf)$/i,
use: 'file-loader?name=../fonts/[name].[ext]',
},
{
test: /\.(png|jpe?g|gif|svg)$/i,
use: [
'file-loader?name=../img/[name].[ext]',
{
loader: 'img-loader',
options: {
enabled: !dev,
plugins: [
require('imagemin-gifsicle')({}),
require('imagemin-mozjpeg')({}),
require('imagemin-pngquant')({}),
require('imagemin-svgo')({}),
]
}
}
]
}
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '../css/[name].css',
}),
]
};
if (!dev) {
config.optimization = {
minimizer: [
new UglifyJSPlugin(),
]
};
}
module.exports = config;