gulp-component is an opinionated generator for web development. Tools for building a great experience across many devices. A solid starting point for both professionals and newcomers to the industry.
Available | |
---|---|
Browsersync | β |
Pug | β |
Twig | β |
Sass | β |
Less | β |
GulpV4 | β |
Webpack | β |
Typescript | β |
JavaScript ES6+ Support | β |
State Management | β |
PostCSS support | β |
Live Browser Reloading | β |
Code spliting | β |
Optimize Images | β |
Minify Css and Javascript | β |
Unit test | β |
SEO | β |
At present, I officially aim to support the last two versions of the following browsers:
- Chrome
- Edge
- Firefox
- Safari
- Internet Explorer
This is not to say that gulp-simple cannot be used in browsers older than those reflected, but merely that my focus will be on ensuring our layouts work great in the above.
NOTE: For OSX users You may have some issues compiling code during installation of packages. Please install Xcode from App Store first. After Xcode is installed, open Xcode and go to Preferences -> Download -> Command Line Tools -> Install to install command line tools.
NOTE: For Windows users You may have some issues compiling BrowserSync during installation of packages. Please go to http://www.browsersync.io/docs/#windows-users for more information on how to get all the needed dependencies.
Can not install node-gym
Open powershell as Administrator
npm install --global --production windows-build-tools
npm install --global node-gyp
Bring up a terminal and type node --version
.
Node should respond with a version at or above 10.x.x.
If you need to install Node, go to nodejs.org and click on the big green Install button.
Bring up a terminal and type gulp --version
.
If Gulp is installed it should return a version number at or above 4.x.x.
If you need to install/upgrade Gulp, open up a terminal and type in the following:
$ npm install --global gulp
$ npm install --global gulp-cli
This will install Gulp globally. Depending on your user account, you may need to configure your system to install packages globally without administrative privileges.
Next, install the local dependencies requires:
$ npm install
That's it! You should now have everything needed to use the gulp-component.
You may also want to get used to some of the commands available.
There are few commands available to help you build and test sites:
Watch For Changes & Automatically Refresh Across Devices
$ npm start
npm start
task creates the tmp
folder in the root of the project.
This includes linting as well as image, script, stylesheet and HTML optimization.
Also, a browsersync script will be automatically generated, which will take care of precaching your sites resources.
Create component
$ npm run add [component_name][files]
$ npm run add header[.js,.pug,.scss]
Create page
$ npm run add page [page_name][files]
$ npm run add index[.js,.pug,.scss]
Serve the Fully Built & Optimized Site
$ npm run build
npm run build
task creates the build
folder in the root of the project with minifying files. It will help you to create clear instances of code for the production or further implementation.
gulp-component/
β
βββ build/ # Build folder for production
βββ core/ # core
βββ gulp/ # Tasks runner
βββ src/ # Dev source
β
βββ config.js # App's config
βββ gulpfile.babel.js
βββ package.json
src
has the following file structure:
src/
β
βββ app/ # Dev goes here
β βββ components # Components
β βββ helpers
β βββ styles # Global styles
β βββ views
| βββ layouts
β βββ pages
|
βββ assets/ # Assets
β β
β βββ fonts/ # Global fonts
| βββ images/ # Global images
component
has flat structure and all files and folders is optional:
component/
β
βββ fonts/ # Fonts
β βββ Roboto.woff2
β
βββ images/ # Any images for style
β β
β βββ sprite/ # Icons for sprite here (png or svg)
β β βββ mail.png
β β βββ [email protected]
β β
β βββ bg.png
β
βββ symbols/ # Icons for symbol sprite (only svg)
β βββ arrow.svg
β
βββ assets/ # Any assets files
β βββ image.jpg
β
βββ components.js
βββ components.pug
βββ components.scss
β
βββ deps.js # Compoennt dependencies
β
βββ data/ # Teamplate data
| βββ *.json
βββ _test_ # Test component
- App's config - Default settings:
- Templates - JSON data in markup - Pathways - Automatic insert of scripts and styles
- Styles - PostCSS
- SVG symbols - Use SVG - SVG Transformation - Get icons for SVG
- Component dependencies - Modules
- Image optimization
- Automatic creation of files and components
- Fast make components and files from terminal
- Default content in new files
- Bundles
All the basic settings are stored in a single file config.js, this approach allows you to use the same builder for different projects and configure each application individually.
If there is no config.js, then the default settings will be used, after any changes in the configuration, you need to restart the development mode!
module.exports = {
// Used technologies
component: {
templates: '.pug', // '.html' or '.pug' or '.twig'
scripts: {
extension: '.js', // '.js' or '.ts'
syntax: 'class', // Syntax for generate and code
},
styles: '.scss', // '.css' or '.styl' or '.less' or '.scss' or '.sass',
test: false, // Component's unit test generate
data: true, // Template data generate
BEM: false, // Generate BEM folder
prefix: '.component', // Prefix for file
},
// Main build settings
build: {
bundles: ['js', 'css'], // code spliting for page
imagemin: [], // need image optimization, may [ 'png', 'jpg', 'svg', 'gif' ]
mainBundle: 'main', // main bundle name
globalStyles: false, // path (from root) for global styles
zip: true // zip build folder
addVersions: true, // need versions (?v=23413)
HTMLRoot: './', // root for paths at static files in HTML
},
// Production structure
directories: {
base: './',
development: {
source: 'src',
app: 'app',
temporary: 'tmp',
components: 'components',
styles: 'styles',
assets: 'assets',
scripts: 'scripts',
images: 'images',
fonts: 'fonts',
data: 'data',
pages: 'pages',
static: 'static',
favicons: 'favicons',
symbols: 'symbols',
},
production: {
destination: 'build',
styles: 'styles',
scripts: 'scripts',
fonts: 'fonts',
images: 'images',
assets: 'assets',
static: 'static',
favicons: 'favicons',
symbols: 'symbols',
},
},
// Settings for default content in files (details below)
addContent: {},
// Blanks for creating components from the terminal (details below)
createComponent: {},
// Settings for image optimization (details below)
optimization: {},
};
Pug / Twig or plain HTML can be used as a template maker.
Pug is the default, but you can change this in config.js
// config.js
component: {
templates: '.pug', // Pug, I choose you!
...
},
Now the build will look for pug files.
Each component can have a data file [component_name].component.json, this data is available in the markup, for example, we have a message compoennt with a json file:
// message.component.json
{
"greeting": "Hello, world!"
}
This data is easily get from a special object site.jsons
// page.component.pug
h1= site.jsons.message.greeting
// page.component.html
<h1>@@site.jsons.message.greeting</h1>
// page.component.twig
<h1>{{ site.jsons.message.greeting }}</h1>
html and twig are not supported yet
Each component has its own folder with assets, so you need to specify placeholder before specific file.
A placeholder consists of a "@" symbol and a component name.
For example, we have a component with a header/assets/images/1.jpeg image, in the markup, you need to specify the path like this:
img(src='@header/images/1.jpeg', alt="")
There are also special placeholders:
@styles - styles folder
@symbol - way to SVG symbol
@scripts - scripts folder
@favicons - favicons folder
The system of dependencies eliminates the need to connect JS and CSS files to the page with your hands, now it is enough to specify a special comment and everything will be done automatically.
html
head
<!-- GULPC:styles -->
// CSS files will be here
body
...
<!-- GULPC:scripts -->
// and here JS files
As a preprocessor for styles, you can use LESS / Sass / Stylus or use plain CSS.
SCSS is the default, but you can change this in config.js
// config.js
use: {
...
styles: '.scss', // Sass I choose you!
},
Most likely you have some kind of common file with variables or mixins, but in the conditions of independence of the components it will have to be imported into each style separately. To put it mildly, this is not the most convenient option, so there is a better way - you can specify a specific file (or an array of files) in the settings and it will be imported automatically.
// config.js
build: {
...
globalStyles: 'app/styles/global.scss' // Path from root to variables file
},
The following PostCSS plugins are used by default:
- autoprefixer - only in production build
- postcss-sprites - only in production build
- postcss-sort-media-queries - only in production build
- cssnano - only in production build
- css-declaration-sorter - only in production build
In addition to the usual style sprites, you can use SVG symbols in HTML, the icons for this sprite need to be stored in a separate component folder (symbols). For each icon, your ID will be generated according to the componentName__iconName pattern, for example:
header/symbols/rating.svg β #header__rating
There are several options for use SVG, you can embed directly into the HTML code, for this you need to specify a special comment:
<!-- GULPC:symbol -->
Then in the use tag you need only the ID:
svg
use(xlink:href="#header__rating")
The second option is an external file, then a special placeholder must be specified in the use tag:
svg
use(xlink:href="@symbol#header__rating")
If at least one SVG icon is found in the page code, the build will look for a special symbol component at the app development level , you can create two prepend.svg
and append.svg
files inside this compoennt and then the contents of these files will be added to the SVG body (at the beginning and at the end).
In development mode, all icons from all components will be added to the sprite, but only those icons that are in your code (with the Β«correctΒ» ID) will be included in the production build.
You can also add a special key @always before expanding the icon, then it will fall into the sprite anyway:
header/symbols/[email protected]
For any component, you can specify dependencies (other components or modules) in the deps.js file
// deps.js
module.exports = {
modules: [], // Modules
};
Each module is an object with three properties:
// deps.js
module.exports = {
modules: [
{
from: '', // module location (CDN or path from the root)
inject: [], // list of files to be used as separate files
import: [], // list of files to be imported into the common bundle
},
],
};
For example, we have a slider component, for full-fledged work, it needs the slick plugin, which in turn uses the jQuery library:
// slider/deps.js
module.exports = {
modules: [
{
from: 'https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/', // jQuery from CDN
inject: ['jquery.min.js'], // this file will be used on the page separately
},
{
from: 'node_modules/slick-carousel/slick', // get slick from node_modules
inject: ['slick.min.js'], // this file will be used on the page separately
import: ['slick.css'], // this file will be imported into the common bundle
},
],
};
Now when using the slider component on the page, the jQuery library and the slick.min.js plugin will be used too, all the images and fonts from slick.css will automatically be pulled into the build.
- If the module does not have the from property, then the file search will take place in the component itself (in the assets folder).
- Files from CDN can not be imported, only used as external files.
If you need to connect the JS file asynchronously, simply add @async or @defer to the end:
{
from: 'node_modules/slick-carousel/slick',
inject: [ 'slick.min.js@async' ], // this script will be used on the page with the async attribute.
},
For a more subtle use of the module, a special filter function is provided that will be called for each file from inject and import:
filter ( file, node, page, type ) {
// file - full path of the included file
// node - component object with all attributes
// page - page name
// type - use type, 'inject' or 'import'
console.log( node ) // { name: 'link', attrs: { class: 'link' }, tag: 'a' }
return true // the function should return true or false (use or not)
}
Suppose I have a link component and this component sometimes needs a lightbox plugin, but you need to connect it only under certain conditions - when the component has the link_zoom modifier:
// link/deps.js
module.exports = {
modules: [
{
from: 'node_modules/lightbox2/dist/',
inject: ['js/lightbox.js'],
import: ['css/lightbox.css'],
filter(file, node) {
return node.attrs.class.split(' ').includes('link_zoom'); // check
},
},
],
};
A simple check in one line solves the problem, now the module will pull up only at the right moment.
Noted: For now, we are not support import
javascript file. Instead that, you can use ES6 import.
You can enable image compression in config.js
There will be no optimization in the development mode, only during the production build!
// config.js
build: {
...
imagemin: [ 'svg', 'jpg', 'png', 'gif' ] // support for 4 types
},
The imagemin plugin is used for compression, for each type, you can specify your optimization settings, the default will be as follows:
// config.js
optimization: {
jpg: {
progressive: true,
arithmetic: false,
},
png: {
optimizationLevel: 5, // may 0-7
bitDepthReduction: true,
colorTypeReduction: true,
paletteReduction: true,
},
gif: {
optimizationLevel: 1, // may 1-3
interlaced: true
},
// For svg, you need to specify an array with settings!
svg: [
{ cleanupIDs: false },
{ removeViewBox: false },
{ mergePaths: false },
],
// Here you can specify the names (without extensions) that do not need to be optimized.
ignore: []
},
More information about each type of compression settings can be found in the docs:
You just write the BEM code, and the components and files are created automatically.
By default, this feature is turned off, to activate it, you need to add settings to config.js
// config.js
autoCreate: {
onlyOnWatch: true, // create files always or only during watch
folders: [], // the list of directories of the new component, for example: 'img', 'assets'
files: [], // list of files of the new node, for example: '.css', '.js', 'data.json'
levels: [], // levels where components will be created, for example: 'develop'
ignoreNodes: [], // list of nodes that will be completely ignored **
},
** You can use regular expressions here!
Suppose I need to create components at the components folder, each new component must have a style file, a script and a folder for pictures, but at the same time, you need to ignore the elements and not create files for them:
// config.js
autoCreate: {
onlyOnWatch: true, // create files only during watch
folders: [ 'assets' ], // assets folder created for new components
files: [ '.scss', '.js' ], // new node will have style and script
levels: [ 'components' ], // new components are created only at components folder
ignoreNodes: [ /__[\w]/i ], // all elements will be ignored
},
Good, but with such settings, each JS and CSS file will also be created for each component modifier, if you do not need it, you can add more settings:
// config.js
autoCreate: {
onlyOnWatch: true,
folders: [ 'img', 'assets' ],
files: [ '.css', '.js' ],
levels: [ 'develop' ],
ignoreNodes: [ /__[\w]/i ],
ignoreStyle: [ /[a-z\d](_|--)[a-z\d]/i ], // ignore modifiers when creating styles
ignoreScript: [ /[a-z\d](_|--)[a-z\d]/i ], // ignore modifiers when creating scripts
ignoreTemplate: [], // by analogy, you can specify for templates
},
In fact, we could just ban modifiers as well as elements, but to demonstrate all the possibilities let it be so :)
If for some reason the automatic creation of files and components does not fit, then you can quickly create components and files from the terminal with a simple command npm run add
.
If any files and folders already exist, they will simply be ignored. When using the zsh command shell, you need to escape the square brackets or take the command in quotes!
Create a component header and footer with additional files:
npm run add header[.scss,.js] footer[.pug]
Result: A "header" folder will be created
A "header/header.component.scss" file will be created
A "header/header.component.js" file will be created
A "footer" folder will be created
A "footer/footer.component.pug" file will be created
You can create elements and modifiers:
npm run add header__nav[.scss,.js] footer__inner[.scss] footer_home[.scss]
Result: A "header" folder will be created
A "header/header__nav/header__logo.component.css" file will be created
A "header/header__nav/header__logo.component.js" file will be created
A "footer" folder will be created
A "footer/footer__inner/footer__inner.scss" file will be created
A "footer/footer__home/footer__home.scss" file will be created
By default, all components are created at the components folder, but you can specify the path directly through the colon:
npm run add common/card[.js,.scss] :customPath
Result:
A "common" folder will be created A "common/card" folder will be created
A "common/card/card.component.js" file will be created
A "common/card/card.component.scss" file will be created
npm run add card[.js,.scss] :shared
Result:
A "shared" folder will be created A "shared/card" folder will be created
A "shared/card/card.component.js" file will be created
A "shared/card/card.component.scss" file will be created
You can also quickly create pages, for this you need to specify the keyword page after add:
npm run add page index catalog about.html
Result:
A "pages" folder will be created
A "pages/index.component.pug" file will be created _
A "pages/catalog.component.pug" file will be created _
A "pages/about.component.html" file will be created
------
* If the page extension is not specified, it will be taken from config.js
If you don't want to list files and folders every time, you can create blanks in config.js
// config.js
createComponent: {
b: ['.js', '.scss', '.pug', 'images'];
}
Now quite well:
npm run add header[b]
Result:
A "header" folder will be created
A "header/header.component.js" file will be created
A "header/header.component.scss" file will be created
A "header/header.component.pug" file will be created
A "header/img" folder will be created
When creating files automatically or by hand, its may contain default content, for this you need to add settings in config.js
// config.js
addContent: {
page: {
pug: 'I make [name] page.', // [name] will be replaced by the page name
},
component: {
scss: '.[name] {}' // [name] will be replaced with the name of the scss file
},
}
Now when creating a SCSS file npm run add header[.scss]
its contents will be:
.header {
}
You can specify the empty content directly through the colon: with notemplate
npm run add card[.js,.scss] :noTemplate
By default, when you generate component with the :customPath, it's will not have content
By analogy, you can add content for any new files.
For each page, you can compile scripts and styles separately, for this you need to add settings to config.js:
// config.js
build: {
...
bundles: [ 'css', 'js' ],
...
}
Now for each page will be compiled its own CSS and JS.
In development mode, no bundles are created, only in production build!
Inspiration from BEMTO