1
0
mirror of https://github.com/locomotivemtl/locomotive-boilerplate.git synced 2026-01-15 00:55:08 +08:00

Merge pull request #95 from locomotivemtl/mcaskill-refactor-build

Refactor build tasks and config file
This commit is contained in:
Chauncey McAskill
2021-09-21 17:58:47 -04:00
committed by GitHub
34 changed files with 1020 additions and 274 deletions

View File

@@ -10,25 +10,45 @@
| Name | Version |
| ---------- | -------- |
| [Node] | > 14.15 |
| [Node] | > 14.17 |
[Node]: https://nodejs.org/en/
[Node]: https://nodejs.org/en/
You can use [nvm](https://github.com/nvm-sh/nvm) to install the node version in `.nvmrc`.
## Installation
```sh
npm i
```
## Usage
```sh
# start it
npm start
```
## Configuration
Change the mentions of `locomotive-boilerplate` for your project's name in `mconfig.json`. Legacy from [modularBP](https://github.com/modularorg/modularbp).
There are a few occurrences that should be renamed for your project:
* [package.json](package.json):
* Package name: `@locomotivemtl/boilerplate`
* Package title: `Locomotive Boilerplate`
* [package-lock.json](package-lock.json):
* Package name: `@locomotivemtl/boilerplate`
* [loconfig.json](loconfig.json):
* Browser Sync proxy URL: `locomotive-boilerplate.test`
Remove `paths.url` to use Browser Sync's built-in server which uses `paths.dest`.
* View path: `./views/boilerplate/template`
* [environment.js](assets/scripts/utils/environment.js):
* Application name: `Boilerplate`
* [site.webmanifest](www/site.webmanifest):
* Manifest name: `Locomotive Boilerplate`
* Manifest short name: `Boilerplate`
* HTML files:
* Page title: `Locomotive Boilerplate`
## Build
@@ -41,11 +61,12 @@ npm start
npm run build
```
## Styles
[Sass](https://github.com/sass/node-sass) is our CSS preprocessor. [Autoprefixer](https://github.com/postcss/autoprefixer) is also included.
#### Architecture
[ITCSS](https://github.com/itcss) is our CSS architecture.
* `settings`: Global variables, site-wide settings, config switches, etc.
@@ -60,11 +81,15 @@ npm run build
[_source_](https://github.com/inuitcss/inuitcss#css-directory-structure)
#### Naming
We use a simplified [BEM](https://github.com/bem) syntax.
`.block .block_element -modifier`
```
.block .block_element -modifier
```
#### Namespaces
We namespace our classes for more [transparency](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/).
* `o-`: Object that it may be used in any number of unrelated contexts to the one you can currently see it in. Making modifications to these types of class could potentially have knock-on effects in a lot of other unrelated places.
@@ -76,6 +101,7 @@ We namespace our classes for more [transparency](https://csswizardry.com/2015/03
[_source_](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#the-namespaces)
#### Example
```html
<div class="c-block -large">
<div class="c-block_layout o-layout">
@@ -105,17 +131,20 @@ We namespace our classes for more [transparency](https://csswizardry.com/2015/03
```
## Scripts
[modularJS](https://github.com/modularorg/modularjs) is a small framework we use on top of ES modules. It compiles with [Rollup](https://github.com/rollup/rollup) and [Babel](https://github.com/babel/babel).
#### Why
- Automatically init visible modules.
- Easily call other modules methods.
- Quickly set scoped events with delegation.
- Simply select DOM elements scoped in their module.
* Automatically init visible modules.
* Easily call other modules methods.
* Quickly set scoped events with delegation.
* Simply select DOM elements scoped in their module.
[_source_](https://github.com/modularorg/modularjs#why)
#### Example
```html
<div data-module-example>
<div data-example="main">
@@ -124,8 +153,9 @@ We namespace our classes for more [transparency](https://csswizardry.com/2015/03
<button data-example="load">More</button>
</div>
```
```js
import { module } from 'modujs';
import { module } from 'modujs';
export default class extends module {
constructor(m) {
@@ -147,9 +177,11 @@ export default class extends module {
[Learn more](https://github.com/modularorg/modularjs)
## Page transitions
[modularLoad](https://github.com/modularorg/modularload) is used for page transitions and lazy loading.
#### Example
```html
<nav>
<a href="/">Home</a>
@@ -175,15 +207,18 @@ this.load = new modularLoad({
[Learn more](https://github.com/modularorg/modularload)
## Scroll detection
[Locomotive Scroll](https://github.com/locomotivemtl/locomotive-scroll) is used for elements in viewport detection and smooth scrolling with parallax.
[Locomotive Scroll](https://github.com/locomotivemtl/locomotive-scroll) is used for elements in viewport detection and smooth scrolling with parallax.
#### Example
```html
<div data-module-scroll>
<div data-scroll>Trigger</div>
<div data-scroll data-scroll-speed="1">Parallax</div>
</div>
```
```js
import LocomotiveScroll from 'locomotive-scroll';

View File

@@ -1,4 +1,4 @@
import { module } from 'modujs';
import { module } from 'modujs';
export default class extends module {
constructor(m) {
@@ -6,6 +6,5 @@ export default class extends module {
}
init() {
}
}

View File

@@ -1,4 +1,4 @@
import { module } from 'modujs';
import { module } from 'modujs';
import modularLoad from 'modularload';
export default class extends module {

View File

@@ -1,9 +1,9 @@
import { buildScripts } from './scripts.js';
import { concatVendors } from './concat.js';
import { compileStyles } from './styles.js' ;
import { generateSpriteSVG } from './svgs.js' ;
import concatFiles from './tasks/concats.js';
import compileScripts from './tasks/scripts.js';
import compileStyles from './tasks/styles.js' ;
import compileSVGs from './tasks/svgs.js' ;
buildScripts();
concatVendors();
concatFiles();
compileScripts();
compileStyles();
generateSpriteSVG();
compileSVGs();

View File

@@ -1,27 +0,0 @@
import paths from '../mconfig.json';
import message from './utils/message.js';
import fs from 'fs';
import concat from 'concat';
export function concatVendors() {
console.time('Concat in');
// Get all files in scripts/vendors/
const files = fs.readdirSync(paths.scripts.vendors.src);
// Exclude files that are not JavaScript
var jsFiles = files.filter((file) => {
return file.includes('.js');
});
// Prepend absolute path
jsFiles = jsFiles.map((file) => {
return `${paths.scripts.vendors.src + file}`;
});
// add files in node_modules example:
// jsFiles.push('node_modules/gsap/dist/gsap.min.js');
concat(jsFiles, paths.scripts.dest + paths.scripts.vendors.main + '.js').then(() => {
message('Vendors concatenated', 'success', 'Concat in');
})
}

View File

@@ -1,9 +0,0 @@
import notifier from 'node-notifier';
export default function notification({ title, message }) {
notifier.notify({
title: title,
message: message,
icon: 'https://user-images.githubusercontent.com/4596862/54868065-c2aea200-4d5e-11e9-9ce3-e0013c15f48c.png'
});
}

View File

@@ -1,29 +0,0 @@
import esbuild from 'esbuild';
import paths from '../mconfig.json';
import message from './utils/message.js';
import notification from './notification.js';
export function buildScripts() {
console.time('JS built in');
esbuild.build({
entryPoints: [ paths.scripts.src + paths.scripts.main + '.js' ],
bundle: true,
minify: true,
sourcemap: true,
color: true,
logLevel: 'error',
target: [ 'es2015' ],
outfile: paths.scripts.dest + paths.scripts.main + '.js'
}).catch((e) => {
// errors managments (already done in esbuild)
notification({
title: 'Javascript built failed 🚨',
message: `${e.errors[0].text} in ${e.errors[0].location.file} line ${e.errors[0].location.line}`
});
}).then(() => {
message('Javascript built','success', 'JS built in')
})
}

View File

@@ -1,56 +0,0 @@
import sass from 'node-sass';
import paths from '../mconfig.json';
import fs from 'fs';
import message from './utils/message.js';
import notification from './notification.js';
export function compileStyles() {
console.time('Styles built in');
// Compile main scss
sass.render({
file: paths.styles.src + paths.styles.main + '.scss',
outFile: paths.styles.dest + paths.styles.main + '.css',
outputStyle: 'compressed',
sourceMap: true
}, (error, result) => {
if (error) {
message('Error compiling main.scss', 'error');
console.log(error.formatted);
notification({
title: 'main.scss compilation failed 🚨',
message: `${error.formatted}`
});
} else {
message('Styles built', 'success', 'Styles built in');
}
if (!error){
// No errors during the compilation, write this result on the disk
fs.writeFile(paths.styles.dest + paths.styles.main + '.css', result.css, (err) => {});
}
});
console.time('Critical style built in');
// Compile critical scss
sass.render({
file: paths.styles.src + paths.styles.critical + '.scss',
outFile: paths.styles.dest + paths.styles.critical + '.css',
outputStyle: 'compressed',
sourceMap: true
}, (error, result) => {
if (error) {
message('Error compiling critical.scss', 'error');
console.log(error);
} else {
message('Critical style built', 'success', 'Critical style built in');
}
if (!error){
// No errors during the compilation, write this result on the disk
fs.writeFile(paths.styles.dest + paths.styles.critical + '.css', result.css, (err) => {});
}
});
}

View File

@@ -1,19 +0,0 @@
import mixer from 'svg-mixer';
import paths from '../mconfig.json';
import message from './utils/message.js';
export function generateSpriteSVG() {
console.time('Sprite generated in');
// Write sprite content on disk
mixer([
paths.svgs.src + '*.svg'
], {
spriteConfig: {
usages: false
}
}).then((result) => {
result.write(paths.svgs.dest + 'sprite.svg');
message('SVG Sprite generated', 'success', 'Sprite generated in');
});
}

48
build/tasks/concats.js Normal file
View File

@@ -0,0 +1,48 @@
import loconfig from '../../loconfig.json';
import glob from '../utils/glob.js';
import message from '../utils/message.js';
import notification from '../utils/notification.js';
import template from '../utils/template.js';
import concat from 'concat';
import { basename } from 'node:path';
/**
* Concatenates groups of files.
*
* @async
* @return {Promise}
*/
export default async function concatFiles() {
loconfig.tasks.concats.forEach(async ({
includes,
outfile
}) => {
const filename = basename(outfile || 'undefined');
const timeLabel = `${filename} concatenated in`;
console.time(timeLabel);
try {
includes = includes.map((path) => template(path));
outfile = template(outfile);
const files = await glob(includes);
await concat(files, outfile);
if (files.length) {
message(`${filename} concatenated`, 'success', timeLabel);
} else {
message(`${filename} is empty`, 'notice', timeLabel);
}
} catch (err) {
message(`Error concatenating ${filename}`, 'error');
message(err);
notification({
title: `${filename} concatenation failed 🚨`,
message: `${err.name}: ${err.message}`
});
}
});
};

61
build/tasks/scripts.js Normal file
View File

@@ -0,0 +1,61 @@
import loconfig from '../../loconfig.json';
import message from '../utils/message.js';
import notification from '../utils/notification.js';
import template from '../utils/template.js';
import esbuild from 'esbuild';
import { basename } from 'node:path';
/**
* Bundles and minifies main JavaScript files.
*
* @async
* @return {Promise}
*/
export default async function compileScripts() {
loconfig.tasks.scripts.forEach(async ({
includes,
outdir = '',
outfile = ''
}) => {
const filename = basename(outdir || outfile || 'undefined');
const timeLabel = `${filename} compiled in`;
console.time(timeLabel);
try {
includes = includes.map((path) => template(path));
if (outdir) {
outdir = template(outdir);
} else if (outfile) {
outfile = template(outfile);
} else {
throw new TypeError(
'Expected \'outdir\' or \'outfile\''
);
}
await esbuild.build({
entryPoints: includes,
bundle: true,
minify: true,
sourcemap: true,
color: true,
logLevel: 'error',
target: [
'es2015',
],
outdir,
outfile
});
message(`${filename} compiled`, 'success', timeLabel);
} catch (err) {
// errors managments (already done in esbuild)
notification({
title: `${filename} compilation failed 🚨`,
message: `${err.errors[0].text} in ${err.errors[0].location.file} line ${err.errors[0].location.line}`
});
}
});
};

101
build/tasks/styles.js Normal file
View File

@@ -0,0 +1,101 @@
import loconfig from '../../loconfig.json';
import message from '../utils/message.js';
import notification from '../utils/notification.js';
import postcss from '../utils/postcss.js';
import template from '../utils/template.js';
import { writeFile } from 'node:fs/promises';
import { basename } from 'node:path';
import { promisify } from 'node:util';
import sass from 'node-sass';
const sassRender = promisify(sass.render);
/**
* Compiles and minifies main Sass files to CSS.
*
* @async
* @return {Promise}
*/
export default async function compileStyles() {
loconfig.tasks.styles.forEach(async ({
infile,
outfile
}) => {
const name = basename((outfile || 'undefined'), '.css');
const timeLabel = `${name}.css compiled in`;
console.time(timeLabel);
try {
infile = template(infile);
outfile = template(outfile);
let result = await sassRender({
file: infile,
omitSourceMapUrl: true,
outFile: outfile,
outputStyle: 'compressed',
sourceMap: true,
sourceMapContents: true
});
if (postcss) {
result = await postcss.process(result.css, {
from: outfile,
to: outfile,
map: {
annotation: false,
inline: false,
sourcesContent: true
}
});
if (result.warnings) {
const warnings = result.warnings();
if (warnings.length) {
message(`Error processing ${name}.css`, 'warning');
warnings.forEach((warn) => {
message(warn.toString());
});
}
}
}
writeFile(outfile, result.css).then(() => {
if (result.css) {
message(`${name}.css compiled`, 'success', timeLabel);
} else {
message(`${name}.css is empty`, 'notice', timeLabel);
}
}).catch((err) => {
message(`Error compiling ${name}.css`, 'error');
message(err);
notification({
title: `${name}.css save failed 🚨`,
message: `Could not save stylesheet to ${name}.css`
});
});
if (result.map) {
writeFile(outfile + '.map', result.map.toString()).catch((err) => {
message(`Error compiling ${name}.css.map`, 'error');
message(err);
notification({
title: `${name}.css.map save failed 🚨`,
message: `Could not save sourcemap to ${name}.css.map`
});
});
}
} catch (err) {
message(`Error compiling ${name}.scss`, 'error');
message(err.formatted || err);
notification({
title: `${name}.scss compilation failed 🚨`,
message: (err.formatted || `${err.name}: ${err.message}`)
});
}
});
};

47
build/tasks/svgs.js Normal file
View File

@@ -0,0 +1,47 @@
import loconfig from '../../loconfig.json';
import message from '../utils/message.js';
import notification from '../utils/notification.js';
import template from '../utils/template.js';
import { basename } from 'node:path';
import mixer from 'svg-mixer';
/**
* Generates and transforms SVG spritesheets.
*
* @async
* @return {Promise}
*/
export default async function compileSVGs() {
loconfig.tasks.svgs.forEach(async ({
includes,
outfile
}) => {
const filename = basename(outfile || 'undefined');
const timeLabel = `${filename} compiled in`;
console.time(timeLabel);
try {
includes = includes.map((path) => template(path));
outfile = template(outfile);
const result = await mixer(includes, {
spriteConfig: {
usages: false
}
});
await result.write(outfile);
message(`${filename} compiled`, 'success', timeLabel);
} catch (err) {
message(`Error compiling ${filename}`, 'error');
message(err);
notification({
title: `${filename} compilation failed 🚨`,
message: `${err.name}: ${err.message}`
});
}
});
};

86
build/utils/glob.js Normal file
View File

@@ -0,0 +1,86 @@
/**
* @file Retrieve the first available glob library.
*
* Note that options vary between libraries.
*
* Candidates:
* - {@link https://npmjs.com/package/tiny-glob tiny-glob}
* - {@link https://npmjs.com/package/globby}
* - {@link https://npmjs.com/package/fast-glob fast-glob}
* - {@link https://npmjs.com/package/glob glob}
*/
import { promisify } from 'node:util';
/**
* @type {string[]} A list of packages to attempt import.
*/
const candidates = [
'tiny-glob',
'globby',
'fast-glob',
'glob',
];
export default await importGlob();
/**
* Imports the first available glob function.
*
* @throws {TypeError} If no glob library was found.
* @return {function}
*/
async function importGlob() {
let glob, module;
for (let name of candidates) {
try {
module = await import(name);
if (typeof module.default !== 'function') {
throw new TypeError(`Expected ${name} to be a function`);
}
/**
* Wrap the function to ensure
* a common pattern.
*/
switch (name) {
case 'tiny-glob':
return createArrayableGlob(module.default, {
filesOnly: true
});
case 'glob':
return promisify(module.default);
default:
return module.default;
}
} catch (err) {
// swallow this error; skip to the next candidate.
}
}
throw new TypeError(
`No glob library was found, expected one of: ${modules.join(', ')}`
);
}
/**
* Creates a wrapper function for the glob function
* to provide support for arrays of patterns.
*
* @param {function} glob - The glob function.
* @param {object} options - The glob options.
* @return {function}
*/
function createArrayableGlob(glob, options) {
return (patterns, options) => {
const globs = patterns.map((pattern) => glob(pattern, options));
return Promise.all(globs).then((files) => {
return [].concat.apply([], files);
});
};
}

View File

@@ -1,19 +1,51 @@
/**
* @file Provides a decorator for console messages.
*/
import kleur from 'kleur';
export default function message(text, type, timerId) {
if (type === 'success') {
console.log(kleur.bgGreen().black(`${text}`));
/**
* Outputs a message to the console.
*
* @param {string} text - The message to output.
* @param {string} [type] - The type of message.
* @param {string} [timerID] - The console time label to output.
*/
export default function message(text, type, timerID) {
switch (type) {
case 'success':
console.log('✅ ', kleur.bgGreen().black(text));
break;
if (timerId !== undefined) {
console.timeEnd(timerId)
}
} else if (type === 'error') {
console.log(kleur.red().underline(`${text}`));
} else if (type === 'waiting') {
console.log(kleur.blue().italic(`${text}`));
} else {
console.log(text);
case 'notice':
console.log(' ', kleur.bgBlue().black(text));
break;
case 'error':
console.log('❌ ', kleur.bgRed().black(text));
break;
case 'warning':
console.log('⚠️ ', kleur.bgYellow().black(text));
break;
case 'waiting':
console.log('⏱ ', kleur.blue().italic(text));
if (timerID != null) {
console.timeLog(timerID);
timerID = null;
}
break;
default:
console.log(text);
break;
}
if (timerID != null) {
console.timeEnd(timerID);
}
console.log('');
}
};

View File

@@ -0,0 +1,29 @@
import notifier from 'node-notifier';
/**
* Sends a cross-platform native notification.
*
* Wraps around node-notifier to assign default values.
*
* @param {string|object} options - The notification options or a message.
* @param {string} options.title - The notification title.
* @param {string} options.message - The notification message.
* @param {string} options.icon - The notification icon.
*/
export default function notification(options) {
if (typeof options === 'string') {
options = {
message: options
};
} else if (!options.title && !options.message) {
throw new TypeError(
'Notification expects at least a \'message\' parameter'
);
}
if (typeof options.icon === 'undefined') {
options.icon = 'https://user-images.githubusercontent.com/4596862/54868065-c2aea200-4d5e-11e9-9ce3-e0013c15f48c.png';
}
notifier.notify(options);
};

14
build/utils/postcss.js Normal file
View File

@@ -0,0 +1,14 @@
/**
* @file If available, returns the PostCSS processor with any plugins.
*/
try {
var { default: postcss } = await import('postcss');
let { default: autoprefixer } = await import('autoprefixer');
postcss = postcss([ autoprefixer ]);
} catch (err) {
postcss = null;
}
export default postcss;

111
build/utils/template.js Normal file
View File

@@ -0,0 +1,111 @@
/**
* @file Provides simple template tags.
*/
import loconfig from '../../loconfig.json';
const templateData = flatten({
paths: loconfig.paths
});
/**
* Replaces all template tags from a map of keys and values.
*
* If replacement pairs contain a mix of substrings, regular expressions,
* and functions, regular expressions are executed last.
*
* @param {string} input - The string being searched and replaced on.
* @param {object} data - An object in the form `{ 'from': 'to', … }`.
* @return {string} Returns the translated string.
*/
export default function template(input, data) {
const tags = [];
if (data) {
data = flatten(data);
} else {
data = templateData;
}
for (let tag in data) {
tags.push(escapeRegExp(tag));
}
if (tags.length === 0) {
return input;
}
const search = new RegExp('\\{%\\s*(' + tags.join('|') + ')\\s*%\\}', 'g');
return input.replace(search, (match, key) => {
let value = data[key];
switch (typeof value) {
case 'function':
/**
* Retrieve the offset of the matched substring `args[0]`
* and the whole string being examined `args[1]`.
*/
let args = Array.prototype.slice.call(arguments, -2);
return value.call(data, match, args[0], args[1]);
case 'string':
case 'number':
return value;
}
return '';
});
};
/**
* Creates a new object with all nested object properties
* concatenated into it recursively.
*
* Nested keys are flattened into a property path:
*
* ```js
* {
* a: {
* b: {
* c: 1
* }
* },
* d: 1
* }
* ```
*
* ```js
* {
* "a.b.c": 1,
* "d": 1
* }
* ```
*
* @param {object} input - The object to flatten.
* @param {string} prefix - The parent key prefix.
* @param {object} target - The object that will receive the flattened properties.
* @return {object} Returns the `target` object.
*/
function flatten(input, prefix, target = {}) {
for (let key in input) {
let field = (prefix ? prefix + '.' + key : key);
if (typeof input[key] === 'object') {
flatten(input[key], field, target);
} else {
target[field] = input[key];
}
}
return target;
}
/**
* Quotes regular expression characters.
*
* @param {string} str - The input string.
* @return {string} Returns the quoted (escaped) string.
*/
function escapeRegExp(str) {
return str.replace(/[\[\]\{\}\(\)\-\*\+\?\.\,\\\^\$\|\#\s]/g, '\\$&');
}

View File

@@ -1,9 +1,13 @@
import { buildScripts } from './scripts.js';
import { concatVendors } from './concat.js';
import { compileStyles } from './styles.js' ;
import { generateSpriteSVG } from './svgs.js';
import paths from '../mconfig.json';
import loconfig from '../loconfig.json';
import concatFiles from './tasks/concats.js';
import compileScripts from './tasks/scripts.js';
import compileStyles from './tasks/styles.js' ;
import compileSVGs from './tasks/svgs.js';
import template from './utils/template.js';
import server from 'browser-sync';
import { join } from 'node:path';
const { paths, tasks } = loconfig;
const serverConfig = {
open: false,
@@ -23,45 +27,46 @@ if (typeof paths.url === 'string' && paths.url.length > 0) {
// Start the Browsersync server
server.init(serverConfig);
// Build scripts, compile styles, concat vendors and generate the svgs sprite on first hit
buildScripts();
concatVendors();
// Build scripts, compile styles, concat files,
// and generate spritesheets on first hit
concatFiles();
compileScripts();
compileStyles();
generateSpriteSVG();
compileSVGs();
// and call any methods on it.
server.watch(
[
paths.views.src,
paths.scripts.dest + paths.scripts.main + '.js',
paths.scripts.dest + paths.scripts.vendors.main + '.js',
paths.styles.dest + paths.styles.main + '.css',
paths.svgs.dest + 'sprite.svg'
join(paths.scripts.dest, '*.js'),
join(paths.styles.dest, '*.css'),
join(paths.svgs.dest, '*.svg'),
]
).on('change', server.reload);
// Watch scripts
server.watch(
[
paths.scripts.src + '**/*.js'
join(paths.scripts.src, '**/*.js'),
]
).on('change', () => {
buildScripts();
compileScripts();
});
// Watch scripts vendors
// Watch concats
server.watch(
[
paths.scripts.vendors.src + '*.js'
]
tasks.concats.reduce(
(patterns, { includes }) => patterns.concat(includes),
[]
).map((path) => template(path))
).on('change', () => {
concatVendors();
concatFiles();
});
// Watch styles
server.watch(
[
paths.styles.src + '**/*.scss'
join(paths.styles.src, '**/*.scss'),
]
).on('change', () => {
compileStyles();
@@ -70,8 +75,8 @@ server.watch(
// Watch svgs
server.watch(
[
paths.svgs.src + '*.svg'
join(paths.svgs.src, '*.svg'),
]
).on('change', () => {
generateSpriteSVG();
compileSVGs();
});

61
loconfig.json Executable file
View File

@@ -0,0 +1,61 @@
{
"paths": {
"url": "locomotive-boilerplate.test",
"src": "./assets",
"dest": "./www",
"images": {
"src": "./assets/images"
},
"styles": {
"src": "./assets/styles",
"dest": "./www/assets/styles"
},
"scripts": {
"src": "./assets/scripts",
"dest": "./www/assets/scripts"
},
"svgs": {
"src": "./assets/images/sprite",
"dest": "./www/assets/images"
},
"views": {
"src": "./views/boilerplate/template"
}
},
"tasks": {
"concats": [
{
"includes": [
"{% paths.scripts.src %}/vendors/*.js"
],
"outfile": "{% paths.scripts.dest %}/vendors.js"
}
],
"scripts": [
{
"includes": [
"{% paths.scripts.src %}/app.js"
],
"outfile": "{% paths.scripts.dest %}/app.js"
}
],
"styles": [
{
"infile": "{% paths.styles.src %}/critical.scss",
"outfile": "{% paths.styles.dest %}/critical.css"
},
{
"infile": "{% paths.styles.src %}/main.scss",
"outfile": "{% paths.styles.dest %}/main.css"
}
],
"svgs": [
{
"includes": [
"{% paths.svgs.src %}/*.svg"
],
"outfile": "{% paths.svgs.dest %}/sprite.svg"
}
]
}
}

View File

@@ -1,28 +0,0 @@
{
"url": "locomotive-boilerplate.test",
"src": "./assets/",
"dest": "./www/",
"build": "./build/",
"styles": {
"src": "./assets/styles/",
"dest": "./www/assets/styles/",
"main": "main",
"critical": "critical"
},
"scripts": {
"src": "./assets/scripts/",
"dest": "./www/assets/scripts/",
"main": "app",
"vendors": {
"src": "./assets/scripts/vendors/",
"main": "vendors"
}
},
"svgs": {
"src": "./assets/images/sprite/",
"dest": "./www/assets/images/"
},
"views": {
"src": "./views/boilerplate/template/"
}
}

336
package-lock.json generated
View File

@@ -15,13 +15,16 @@
"svg4everybody": "*"
},
"devDependencies": {
"autoprefixer": "^10.3.4",
"browser-sync": "^2.26.13",
"concat": "^1.0.3",
"esbuild": "^0.12.28",
"kleur": "^4.1.4",
"node-notifier": "^10.0.0",
"node-sass": "^6.0.1",
"svg-mixer": "^2.3.14"
"postcss": "^8.3.6",
"svg-mixer": "^2.3.14",
"tiny-glob": "^0.2.9"
},
"engines": {
"node": ">=14.17"
@@ -291,6 +294,33 @@
"node": ">= 4.5.0"
}
},
"node_modules/autoprefixer": {
"version": "10.3.4",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.4.tgz",
"integrity": "sha512-EKjKDXOq7ug+jagLzmnoTRpTT0q1KVzEJqrJd0hCBa7FiG0WbFOBCcJCy2QkW1OckpO3qgttA1aWjVbeIPAecw==",
"dev": true,
"dependencies": {
"browserslist": "^4.16.8",
"caniuse-lite": "^1.0.30001252",
"colorette": "^1.3.0",
"fraction.js": "^4.1.1",
"normalize-range": "^0.1.2",
"postcss-value-parser": "^4.1.0"
},
"bin": {
"autoprefixer": "bin/autoprefixer"
},
"engines": {
"node": "^10 || ^12 || >=14"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
"peerDependencies": {
"postcss": "^8.1.0"
}
},
"node_modules/aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@@ -945,6 +975,29 @@
"node": ">=6"
}
},
"node_modules/browserslist": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz",
"integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==",
"dev": true,
"dependencies": {
"caniuse-lite": "^1.0.30001254",
"colorette": "^1.3.0",
"electron-to-chromium": "^1.3.830",
"escalade": "^3.1.1",
"node-releases": "^1.1.75"
},
"bin": {
"browserslist": "cli.js"
},
"engines": {
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
}
},
"node_modules/bs-recipes": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz",
@@ -1012,6 +1065,16 @@
"node": ">=6"
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001257",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz",
"integrity": "sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA==",
"dev": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
}
},
"node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -1114,6 +1177,12 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"node_modules/colorette": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
"integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==",
"dev": true
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -1561,6 +1630,12 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
"dev": true
},
"node_modules/electron-to-chromium": {
"version": "1.3.838",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.838.tgz",
"integrity": "sha512-65O6UJiyohFAdX/nc6KJ0xG/4zOn7XCO03kQNNbCeMRGxlWTLzc6Uyi0tFNQuuGWqySZJi8CD2KXPXySVYmzMA==",
"dev": true
},
"node_modules/emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
@@ -2014,6 +2089,19 @@
"node": ">= 0.12"
}
},
"node_modules/fraction.js": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz",
"integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==",
"dev": true,
"engines": {
"node": "*"
},
"funding": {
"type": "patreon",
"url": "https://www.patreon.com/infusion"
}
},
"node_modules/fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -2418,6 +2506,18 @@
"node": ">=6"
}
},
"node_modules/globalyzer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
"dev": true
},
"node_modules/globrex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
"dev": true
},
"node_modules/globule": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
@@ -3835,6 +3935,18 @@
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
"dev": true
},
"node_modules/nanoid": {
"version": "3.1.25",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
"integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==",
"dev": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -4000,6 +4112,12 @@
"node": ">= 8"
}
},
"node_modules/node-releases": {
"version": "1.1.75",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz",
"integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==",
"dev": true
},
"node_modules/node-sass": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.1.tgz",
@@ -4103,6 +4221,15 @@
"node": ">=0.10.0"
}
},
"node_modules/normalize-range": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
"integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/normalize.css": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
@@ -4385,17 +4512,17 @@
}
},
"node_modules/postcss": {
"version": "7.0.36",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
"version": "8.3.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz",
"integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==",
"dev": true,
"dependencies": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
"colorette": "^1.2.2",
"nanoid": "^3.1.23",
"source-map-js": "^0.6.2"
},
"engines": {
"node": ">=6.0.0"
"node": "^10 || ^12 || >=14"
},
"funding": {
"type": "opencollective",
@@ -4423,7 +4550,25 @@
"postcss": "^7.0.0"
}
},
"node_modules/postcss/node_modules/supports-color": {
"node_modules/postcss-prefix-selector/node_modules/postcss": {
"version": "7.0.36",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
"dev": true,
"dependencies": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
},
"engines": {
"node": ">=6.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
}
},
"node_modules/postcss-prefix-selector/node_modules/supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
@@ -4435,6 +4580,12 @@
"node": ">=6"
}
},
"node_modules/postcss-value-parser": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
"dev": true
},
"node_modules/posthtml": {
"version": "0.11.6",
"resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.11.6.tgz",
@@ -5454,6 +5605,15 @@
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
"integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-resolve": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
@@ -5986,6 +6146,16 @@
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-1.2.0.tgz",
"integrity": "sha1-bchFBSywjr78GHRyO1jySmSMO28="
},
"node_modules/tiny-glob": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
"dev": true,
"dependencies": {
"globalyzer": "0.1.0",
"globrex": "^0.1.2"
}
},
"node_modules/to-array": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
@@ -6617,6 +6787,20 @@
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"dev": true
},
"autoprefixer": {
"version": "10.3.4",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.4.tgz",
"integrity": "sha512-EKjKDXOq7ug+jagLzmnoTRpTT0q1KVzEJqrJd0hCBa7FiG0WbFOBCcJCy2QkW1OckpO3qgttA1aWjVbeIPAecw==",
"dev": true,
"requires": {
"browserslist": "^4.16.8",
"caniuse-lite": "^1.0.30001252",
"colorette": "^1.3.0",
"fraction.js": "^4.1.1",
"normalize-range": "^0.1.2",
"postcss-value-parser": "^4.1.0"
}
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@@ -7145,6 +7329,19 @@
"stream-throttle": "^0.1.3"
}
},
"browserslist": {
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz",
"integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30001254",
"colorette": "^1.3.0",
"electron-to-chromium": "^1.3.830",
"escalade": "^3.1.1",
"node-releases": "^1.1.75"
}
},
"bs-recipes": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz",
@@ -7199,6 +7396,12 @@
}
}
},
"caniuse-lite": {
"version": "1.0.30001257",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz",
"integrity": "sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA==",
"dev": true
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -7282,6 +7485,12 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"colorette": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
"integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==",
"dev": true
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -7647,6 +7856,12 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
"dev": true
},
"electron-to-chromium": {
"version": "1.3.838",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.838.tgz",
"integrity": "sha512-65O6UJiyohFAdX/nc6KJ0xG/4zOn7XCO03kQNNbCeMRGxlWTLzc6Uyi0tFNQuuGWqySZJi8CD2KXPXySVYmzMA==",
"dev": true
},
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
@@ -8020,6 +8235,12 @@
"mime-types": "^2.1.12"
}
},
"fraction.js": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz",
"integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==",
"dev": true
},
"fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@@ -8347,6 +8568,18 @@
}
}
},
"globalyzer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
"dev": true
},
"globrex": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
"dev": true
},
"globule": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
@@ -9487,6 +9720,12 @@
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
"dev": true
},
"nanoid": {
"version": "3.1.25",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
"integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==",
"dev": true
},
"nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -9611,6 +9850,12 @@
}
}
},
"node-releases": {
"version": "1.1.75",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz",
"integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==",
"dev": true
},
"node-sass": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.1.tgz",
@@ -9688,6 +9933,12 @@
"remove-trailing-separator": "^1.0.1"
}
},
"normalize-range": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
"integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
"dev": true
},
"normalize.css": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
@@ -9905,25 +10156,14 @@
"dev": true
},
"postcss": {
"version": "7.0.36",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
"version": "8.3.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz",
"integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
},
"dependencies": {
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
"colorette": "^1.2.2",
"nanoid": "^3.1.23",
"source-map-js": "^0.6.2"
}
},
"postcss-helpers": {
@@ -9942,8 +10182,36 @@
"dev": true,
"requires": {
"postcss": "^7.0.0"
},
"dependencies": {
"postcss": {
"version": "7.0.36",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
"supports-color": "^6.1.0"
}
},
"supports-color": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"postcss-value-parser": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
"dev": true
},
"posthtml": {
"version": "0.11.6",
"resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.11.6.tgz",
@@ -10826,6 +11094,12 @@
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
"integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
"dev": true
},
"source-map-resolve": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
@@ -11267,6 +11541,16 @@
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-1.2.0.tgz",
"integrity": "sha1-bchFBSywjr78GHRyO1jySmSMO28="
},
"tiny-glob": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
"dev": true,
"requires": {
"globalyzer": "0.1.0",
"globrex": "^0.1.2"
}
},
"to-array": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",

View File

@@ -20,12 +20,15 @@
"svg4everybody": "*"
},
"devDependencies": {
"autoprefixer": "^10.3.4",
"browser-sync": "^2.26.13",
"concat": "^1.0.3",
"esbuild": "^0.12.28",
"kleur": "^4.1.4",
"node-notifier": "^10.0.0",
"node-sass": "^6.0.1",
"svg-mixer": "^2.3.14"
"postcss": "^8.3.6",
"svg-mixer": "^2.3.14",
"tiny-glob": "^0.2.9"
}
}

View File

@@ -2,7 +2,7 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Boilerplate</title>
<title>Email | Locomotive Boilerplate</title>
</head>
<body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
<center>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +0,0 @@
/*# sourceMappingURL=critical.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","file":"critical.css"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@
<html class="is-loading" lang="en" data-page="page">
<head>
<meta charset="utf-8">
<title>Form | Boilerplate</title>
<title>Form | Locomotive Boilerplate</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -20,7 +20,7 @@
<div data-load-container>
<div class="o-scroll" data-module-scroll="main">
<header data-scroll-section>
<a href="/"><h1>Boilerplate</h1></a>
<a href="/"><h1>Locomotive Boilerplate</h1></a>
<nav>
<ul>
<li><a href="images.html">Images</a></li>

View File

@@ -2,7 +2,7 @@
<html class="is-loading" lang="en" data-page="home">
<head>
<meta charset="utf-8">
<title>Images | Boilerplate</title>
<title>Images | Locomotive Boilerplate</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -20,7 +20,7 @@
<div data-load-container>
<div class="o-scroll" data-module-scroll="main">
<header data-scroll-section>
<a href="/"><h1>Boilerplate</h1></a>
<a href="/"><h1>Locomotive Boilerplate</h1></a>
<nav>
<ul>
<li><a href="images.html">Images</a></li>

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<title>Boilerplate</title>
<title>Locomotive Boilerplate</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -38,7 +38,7 @@
<div class="o-scroll" data-module-scroll="main">
<header data-scroll-section>
<a href="/">
<h1>Boilerplate</h1>
<h1>Locomotive Boilerplate</h1>
</a>
<nav>
<ul>

View File

@@ -1,5 +1,5 @@
{
"name": "Boilerplate",
"name": "Locomotive Boilerplate",
"short_name": "Boilerplate",
"icons": [
{