Repository: 2gis/tars Branch: master Commit: 75957b30ed10 Files: 262 Total size: 446.3 KB Directory structure: gitextract_x9whm8un/ ├── .babelrc ├── .browserslistrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── README_RU.md ├── appveyor.yml ├── docs/ │ ├── en/ │ │ ├── changelog.md │ │ ├── css-concat-processing.md │ │ ├── css-manual-processing.md │ │ ├── css-processing.md │ │ ├── faq.md │ │ ├── file-structure.md │ │ ├── fonts-and-misc.md │ │ ├── handlebars-helpers.md │ │ ├── html-processing.md │ │ ├── images-processing.md │ │ ├── js-concat-processing.md │ │ ├── js-processing.md │ │ ├── js-webpack-processing.md │ │ ├── options.md │ │ ├── plugins-options.md │ │ ├── scenarios.md │ │ ├── svg-processing.md │ │ ├── tasks-and-watchers.md │ │ ├── tasks.md │ │ ├── update-guide.md │ │ └── watchers.md │ └── ru/ │ ├── changelog.md │ ├── css-concat-processing.md │ ├── css-manual-processing.md │ ├── css-processing.md │ ├── faq.md │ ├── file-structure.md │ ├── fonts-and-misc.md │ ├── for-contributors.md │ ├── handlebars-helpers.md │ ├── html-processing.md │ ├── images-processing.md │ ├── js-concat-processing.md │ ├── js-processing.md │ ├── js-webpack-processing.md │ ├── options.md │ ├── plugins-options.md │ ├── scenarios.md │ ├── svg-processing.md │ ├── tasks-and-watchers.md │ ├── tasks.md │ ├── update-guide.md │ └── watchers.md ├── gulpfile.js ├── markup/ │ ├── components/ │ │ └── _template/ │ │ ├── _template.js │ │ └── data/ │ │ └── data.js │ └── static/ │ ├── js/ │ │ └── main.js │ └── misc/ │ └── humans.txt ├── package.json ├── plugins-config.json ├── prettier.config.js ├── tars/ │ ├── helpers/ │ │ ├── filter-files-by-path.js │ │ ├── get-templater-name.js │ │ ├── install-additional-deps.js │ │ ├── modify-date-formatter.js │ │ ├── notifier.js │ │ ├── plugins-config-processing.js │ │ ├── set-build-version.js │ │ ├── set-ulimit.js │ │ ├── skip-task-with-empty-pipe.js │ │ ├── start-screen-generator.js │ │ ├── string-helper.js │ │ ├── tars-fs-helper.js │ │ └── watcher-log.js │ ├── tars.js │ ├── tasks/ │ │ ├── css/ │ │ │ ├── compile-css-for-ie8.js │ │ │ ├── compile-css-for-ie9.js │ │ │ ├── compile-css.js │ │ │ ├── compress-css.js │ │ │ ├── helpers/ │ │ │ │ ├── actions-on-sprite-task-skipping.js │ │ │ │ ├── concat-compile-css-task-template.js │ │ │ │ ├── manual-compile-css-task-template.js │ │ │ │ └── sprite-mixins/ │ │ │ │ ├── less-raster-sprite-mixins.less │ │ │ │ ├── less-svg-fallback-sprite-mixins.less │ │ │ │ ├── less-svg-sprite-mixins.less │ │ │ │ ├── scss-raster-sprite-mixins.scss │ │ │ │ ├── scss-svg-fallback-sprite-mixins.scss │ │ │ │ ├── scss-svg-sprite-mixins.scss │ │ │ │ ├── stylus-raster-sprite-mixins.styl │ │ │ │ ├── stylus-svg-fallback-sprite-mixins.styl │ │ │ │ └── stylus-svg-sprite-mixins.styl │ │ │ ├── make-fallback-for-svg.js │ │ │ ├── make-sprite-for-svg.js │ │ │ ├── make-sprite.js │ │ │ └── move-separate.js │ │ ├── html/ │ │ │ ├── compile-templates.js │ │ │ ├── concat-mocks-data.js │ │ │ ├── helpers/ │ │ │ │ ├── generate-static-path.js │ │ │ │ ├── handlebars-helpers.js │ │ │ │ ├── jade-helpers.js │ │ │ │ ├── pages-and-data-files-processing.js │ │ │ │ ├── pug-helpers.js │ │ │ │ └── utils/ │ │ │ │ ├── dates.js │ │ │ │ └── utils.js │ │ │ └── modify-html.js │ │ ├── images/ │ │ │ ├── helpers/ │ │ │ │ └── symbols-data-template.js │ │ │ ├── make-symbols-sprite.js │ │ │ ├── minify-images.js │ │ │ ├── minify-svg.js │ │ │ ├── move-content-img.js │ │ │ ├── move-general-img.js │ │ │ ├── move-plugins-img.js │ │ │ └── raster-svg.js │ │ ├── js/ │ │ │ ├── check.js │ │ │ ├── concat-processing.js │ │ │ ├── helpers/ │ │ │ │ └── separate-files-filter.js │ │ │ ├── move-separate.js │ │ │ ├── processing.js │ │ │ └── webpack-processing.js │ │ ├── main/ │ │ │ ├── build-dev.js │ │ │ ├── build.js │ │ │ ├── create-build.js │ │ │ └── dev.js │ │ ├── other/ │ │ │ ├── move-assets.js │ │ │ ├── move-fonts.js │ │ │ └── move-misc-files.js │ │ └── services/ │ │ ├── clean.js │ │ ├── create-fs.js │ │ ├── init.js │ │ ├── remove-init-fs.js │ │ ├── update-deps.js │ │ └── zip-build.js │ ├── user-tasks/ │ │ ├── example-task.js │ │ └── html/ │ │ └── helpers/ │ │ ├── handlebars-helpers.js │ │ ├── jade-helpers.js │ │ ├── modify-options.js │ │ └── pug-helpers.js │ ├── user-watchers/ │ │ └── example-watcher.js │ └── watchers/ │ ├── css/ │ │ ├── common-css.js │ │ ├── ie8-css.js │ │ ├── ie9-css.js │ │ └── modules-css.js │ ├── js/ │ │ └── all.js │ ├── move/ │ │ ├── assets.js │ │ ├── content-img.js │ │ ├── fonts.js │ │ ├── general-img.js │ │ ├── misc-files.js │ │ ├── plugins-img.js │ │ ├── separate-css.js │ │ └── separate-js.js │ ├── sprite/ │ │ ├── png-sprites.js │ │ ├── svg-sprites.js │ │ └── symbols.js │ └── templates/ │ ├── data-files.js │ └── page-modules.js ├── tars-config.js ├── tars.json ├── templates/ │ ├── handlebars/ │ │ └── markup/ │ │ ├── components/ │ │ │ ├── _template/ │ │ │ │ └── _template.html │ │ │ ├── default_component_scheme.json │ │ │ ├── example/ │ │ │ │ └── example.html │ │ │ ├── footer/ │ │ │ │ └── footer.html │ │ │ └── head/ │ │ │ ├── data/ │ │ │ │ └── data.js │ │ │ └── head.html │ │ └── pages/ │ │ ├── _template.html │ │ └── index.html │ ├── jade/ │ │ └── markup/ │ │ ├── components/ │ │ │ ├── _template/ │ │ │ │ └── _template.jade │ │ │ ├── default_component_scheme.json │ │ │ ├── example/ │ │ │ │ └── example.jade │ │ │ ├── footer/ │ │ │ │ └── footer.jade │ │ │ └── head/ │ │ │ ├── data/ │ │ │ │ └── data.js │ │ │ └── head.jade │ │ └── pages/ │ │ ├── _template.jade │ │ └── index.jade │ ├── less/ │ │ └── markup/ │ │ ├── components/ │ │ │ └── _template/ │ │ │ └── _template.less │ │ └── static/ │ │ └── less/ │ │ ├── GUI.less │ │ ├── common.less │ │ ├── entry/ │ │ │ ├── built-in-partials/ │ │ │ │ ├── _service-ie8.less │ │ │ │ └── _service.less │ │ │ ├── ie/ │ │ │ │ ├── main_ie8.less │ │ │ │ └── main_ie9.less │ │ │ ├── main.less │ │ │ └── partials/ │ │ │ ├── _components-ie8.less │ │ │ ├── _components-ie9.less │ │ │ ├── _components.less │ │ │ ├── _libraries.less │ │ │ └── _plugins.less │ │ ├── etc/ │ │ │ └── etc.less │ │ ├── fonts.less │ │ ├── libraries/ │ │ │ └── library-sample.less │ │ ├── mixins.less │ │ ├── normalize.less │ │ ├── plugins/ │ │ │ └── sample-plugin.less │ │ ├── separate-css/ │ │ │ └── separate-css-sample.css │ │ ├── sprite-generator-templates/ │ │ │ ├── less.sprite.mustache │ │ │ ├── less.svg-fallback-sprite.mustache │ │ │ └── less.svg-sprite.mustache │ │ ├── sprites-less/ │ │ │ ├── sprite-png-ie.less │ │ │ └── sprite-png.less │ │ └── vars.less │ ├── pug/ │ │ └── markup/ │ │ ├── components/ │ │ │ ├── _template/ │ │ │ │ └── _template.pug │ │ │ ├── default_component_scheme.json │ │ │ ├── example/ │ │ │ │ └── example.pug │ │ │ ├── footer/ │ │ │ │ └── footer.pug │ │ │ └── head/ │ │ │ ├── data/ │ │ │ │ └── data.js │ │ │ └── head.pug │ │ └── pages/ │ │ ├── _template.pug │ │ └── index.pug │ ├── scss/ │ │ └── markup/ │ │ ├── components/ │ │ │ └── _template/ │ │ │ └── _template.scss │ │ └── static/ │ │ └── scss/ │ │ ├── GUI.scss │ │ ├── common.scss │ │ ├── entry/ │ │ │ ├── built-in-partials/ │ │ │ │ ├── _service-ie8.scss │ │ │ │ └── _service.scss │ │ │ ├── ie/ │ │ │ │ ├── main_ie8.scss │ │ │ │ └── main_ie9.scss │ │ │ ├── main.scss │ │ │ └── partials/ │ │ │ ├── _components-ie8.scss │ │ │ ├── _components-ie9.scss │ │ │ ├── _components.scss │ │ │ ├── _libraries.scss │ │ │ └── _plugins.scss │ │ ├── etc/ │ │ │ └── etc.scss │ │ ├── fonts.scss │ │ ├── libraries/ │ │ │ └── library-sample.scss │ │ ├── mixins.scss │ │ ├── normalize.scss │ │ ├── plugins/ │ │ │ └── sample-plugin.scss │ │ ├── separate-css/ │ │ │ └── separate-css-sample.css │ │ ├── sprite-generator-templates/ │ │ │ ├── scss.sprite.mustache │ │ │ ├── scss.svg-fallback-sprite.mustache │ │ │ └── scss.svg-sprite.mustache │ │ ├── sprites-scss/ │ │ │ └── sprite-ie.scss │ │ └── vars.scss │ └── stylus/ │ └── markup/ │ ├── components/ │ │ └── _template/ │ │ └── _template.styl │ └── static/ │ └── stylus/ │ ├── GUI.styl │ ├── common.styl │ ├── entry/ │ │ ├── built-in-partials/ │ │ │ ├── _service-ie8.styl │ │ │ └── _service.styl │ │ ├── ie/ │ │ │ ├── main_ie8.styl │ │ │ └── main_ie9.styl │ │ ├── main.styl │ │ └── partials/ │ │ ├── _components-ie8.styl │ │ ├── _components-ie9.styl │ │ ├── _components.styl │ │ ├── _libraries.styl │ │ └── _plugins.styl │ ├── etc/ │ │ └── etc.styl │ ├── fonts.styl │ ├── libraries/ │ │ └── library-sample.styl │ ├── mixins.styl │ ├── normalize.styl │ ├── plugins/ │ │ └── sample-plugin.styl │ ├── separate-css/ │ │ └── separate-css-sample.css │ ├── sprite-generator-templates/ │ │ ├── stylus.sprite.mustache │ │ ├── stylus.svg-fallback-sprite.mustache │ │ └── stylus.svg-sprite.mustache │ ├── sprites-stylus/ │ │ ├── sprite-png-ie.styl │ │ └── sprite-png.styl │ └── vars.styl ├── user-package.json └── webpack.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .babelrc ================================================ { "presets": ["@babel/preset-env"], "ignore": [ "**/babel_ignore_*.js", "*/js/framework/*.js", "*/js/libraries/*.js", "*/js/plugins/*.js", "*/js/separate-js/*.js" ] } ================================================ FILE: .browserslistrc ================================================ > 1% last 2 versions Firefox ESR android 4 ================================================ FILE: .editorconfig ================================================ # editorconfig.org root = true [*] indent_style = space indent_size = 4 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.md] trim_trailing_whitespace = false [node_modules/**.js] codepaint = false [package.json] indent_style = space indent_size = 2 ================================================ FILE: .eslintignore ================================================ **/_*.js plugins-config.json ================================================ FILE: .eslintrc ================================================ { "root": true, "env": { "node": true, "browser": true, "commonjs": true, "jquery": true, "es6": true }, "globals": { "tars": true }, "extends": "eslint:recommended", "parserOptions": { "ecmaVersion": 6, "sourceType": "module" }, "rules": { "indent": [2, 4, {"SwitchCase": 1}], "brace-style": [2, "1tbs"], "camelcase": [2, { "properties": "always" }], "comma-spacing": [2, {"before": false, "after": true}], "comma-style": [2, "last"], "consistent-return": 0, "curly": [2, "all"], "default-case": 2, "dot-notation": [2, { "allowKeywords": true }], "eol-last": 2, "eqeqeq": [2, "smart"], "guard-for-in": 2, "key-spacing": [2, { "beforeColon": false, "afterColon": true }], "new-cap": 2, "new-parens": 2, "no-alert": 2, "no-array-constructor": 2, "no-caller": 2, "no-debugger": 0, "no-delete-var": 2, "no-eval": 0, "no-extra-bind": 2, "no-fallthrough": 2, "no-floating-decimal": 2, "no-implied-eval": 2, "no-invalid-this": 1, "no-iterator": 2, "no-label-var": 2, "no-labels": 2, "no-lone-blocks": 2, "no-loop-func": 1, "no-mixed-spaces-and-tabs": [2, false], "no-multi-spaces": 2, "no-multi-str": 2, "no-native-reassign": 2, "no-nested-ternary": 2, "no-new-func": 2, "no-new-object": 2, "no-new-wrappers": 2, "no-octal": 2, "no-octal-escape": 2, "no-process-exit": 2, "no-proto": 2, "no-redeclare": 2, "no-return-assign": 2, "no-script-url": 2, "no-sequences": 2, "no-shadow": 2, "no-shadow-restricted-names": 2, "no-spaced-func": 2, "no-trailing-spaces": 2, "no-undef": 2, "no-undef-init": 2, "no-undefined": 2, "no-unused-expressions": 2, "no-unused-vars": [1, {"vars": "all", "args": "after-used"}], "no-use-before-define": 2, "no-with": 2, "quotes": [2, "single"], "radix": 2, "semi": [2, "always"], "semi-spacing": [2, {"before": false, "after": true}], "keyword-spacing": 2, "space-before-blocks": [2, "always"], "space-before-function-paren": [2, {"anonymous": "always", "named": "never"}], "space-infix-ops": 2, "space-unary-ops": [2, {"words": true, "nonwords": false}], "spaced-comment": [2, "always", { "exceptions": ["-"]}], "strict": 0, "valid-jsdoc": [0, {"requireReturnDescription": false, "requireReturn": false}], "wrap-iife": [2, "inside"], "yoda": [2, "never"], // Previously on by default in node environment "no-catch-shadow": 0, "no-console": 0, "no-mixed-requires": 2, "no-new-require": 2, "no-path-concat": 2, "global-strict": [0, "always"], "handle-callback-err": [2, "err"], // ES6 "arrow-spacing": [2, {"before": true, "after": true}], "constructor-super": 2, "no-confusing-arrow": 2, "no-class-assign": 2, "no-const-assign": 2, "no-dupe-class-members": 2, "no-this-before-super": 2, "prefer-arrow-callback": 0, "prefer-template": 0, "require-yield": 2, "no-var": 1 } } ================================================ FILE: .gitignore ================================================ node_modules dev .DS_Store ._.DS_Store .tmpTemplater .tmpPreproc .idea npm-debug.log phantomjsdriver.log /nbproject/* **/sprite_96.* **/svg-fallback-sprite.* **/svg-sprite.* .vscode ================================================ FILE: .travis.yml ================================================ language: c os: - linux - osx env: matrix: - export NODE_VERSION="16" matrix: fast_finish: true before_install: - echo $TRAVIS_OS_NAME - 'export TRAVIS_COMMIT_MSG="$(git log --format=%B --no-merges -n 1)"' - export START_FULL_TESTS=$(echo $TRAVIS_COMMIT_MSG | grep '\[full\]' -c) - if [ ${START_FULL_TESTS} = "1" ]; then echo "FULL TESTS!"; fi - git clone https://github.com/creationix/nvm.git ./.nvm - source ./.nvm/nvm.sh - nvm install $NODE_VERSION - nvm use $NODE_VERSION before_script: - npm -v - npm install - npm install -g gulp script: - gulp init - gulp --release --ie ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014-2016, Malko Artem , Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================

English description | Описание на русском

# Maintainer is needed! # ![Tars](https://raw.githubusercontent.com/artem-malko/artwork/master/tars/logo.png) [![Downloads][downloads-image]][npm-url] [![Mac/Linux Build Status](https://img.shields.io/travis/tars/tars/master.svg?label=Mac%20OSX%20%26%20Linux&style=flat-square)](https://travis-ci.org/tars/tars) [![Windows Build status](https://img.shields.io/appveyor/ci/artem-malko/tars/master.svg?label=Windows&style=flat-square)](https://ci.appveyor.com/project/artem-malko/tars/branch/master) [![Gitter](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg?style=flat-square)](https://gitter.im/tars/tars?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) TARS is a builder for modern frontend of any complexity, which is based on [Gulp.js](http://gulpjs.com/). It facilitates and accelerates process of web-development. TARS will be suitable for teams and individual developers. It solves the most routine cases associated with web-development and brings you more pleasure from work. TARS is a framework for gulp, including a set of gulp-tasks. It allows for easy expansion (creating new tasks) and customization (modification of existing tasks), provides comfortable architecture for tasks and watchers storage in the project. To bypass dependencies installation for every TARS project, [TARS-CLI](https://github.com/tars/tars-cli) was created. As such, TARS is not a npm-package by itself. This decision was made so that everyone could comfortably customize the builder for themselves. TARS-CLI is just a simple builder interface, which includes all dependencies for TARS. **It is strongly recommended to use TARS-CLI for development.** You can install TARS-CLI via NPM. More info in [project's repository](https://github.com/tars/tars-cli). **Attention! All docs from branch "master" are written for the last version of TARS. If you have another version of TARS, please, open appropriate release and take docs from there. Besides, you have all docs, which are 100% compatible with your project in the root folder of your project!** ## Basic features Listed below are just a little part of the features. In fact builder has much more. * [Jade](http://jade-lang.com/), [Pug](https://pugjs.org/api/getting-started.html) or [Handlebars](http://handlebarsjs.com/) as html templater. You can also use a regular html. Read more [in docs](/docs/en/html-processing.md). * [Webpack](https://webpack.github.io) (with [Hot Module Replacing](https://webpack.github.io/docs/hot-module-replacement.html)) or simple JavaScript code concatenation into one bundle. * Using json (js-object actually, which can be described in json) to transfer data in templates (optional, but it is a very cool thing that will let you get rid of copypaste). Read more [in docs](/docs/en/html-processing.md#%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8F%D0%BC%D0%B8-%D0%B8-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%BC%D0%B8-%D0%B2-handlebars). * [TARS-CLI](https://github.com/tars/tars-cli) and **auto update of your project**. * You can use ES6 (and some experimental features from ES7) right now. [More info](/docs/en/js-processing.md). * [SCSS (SASS)](http://sass-lang.com/), [LESS](http://www.lesscss.org/) or [Stylus](http://learnboost.github.io/stylus/) as a preprocessor for css. Also it includes a small set of mixins. Sourcemaps are included. You can use .scss and .sass extension then scss is selected as preprocessor. You can use .scss and .sass files together. Read more [in docs](/docs/en/css-processing.md). [PostCSS](https://github.com/postcss/postcss) with [autoprefixer](https://github.com/postcss/autoprefixer) is supported by default and it is really easy [to use additional plugins for PostCSS](/docs/en/options.md#postcss). * No external libraries or plugins (except [html5shiv](https://ru.wikipedia.org/wiki/Html5_Shiv)). Yes, this is a feature because you can choose which library to use. Sourcemaps for JavaScript are included. * [Chokidar](https://github.com/paulmillr/chokidar) module is used to watch files * Optional markup sharing from your local computer to the world. And of course it has livereload in browser (and not just locally) + GUI control panel for devices, to which markup is shared. * [You can easily add new tasks and watchers](/docs/en/tasks-and-watchers.md). There are several examples of how to create and use a new task or watcher inside the TARS. Thereby, it is really easy to add any task from your builder to TARS or integrate TARS into your project. * Smart work with images. First of all with vector (svg). There will be no more hell with markup for screens with high pixel density. TARS supports two workflows of working with SVG: [SVG-sprites](docs/en/svg-processing.md#svg-sprites) and [SVG-symbols](docs/en/svg-processing.md#svg-symbols). * Several modes of assembly (common, with minified files, with hash in the title of css and js files for deployment). * Creating archive with a complete build. ## Documentation It is important! All examples in documentation use the default settings. * [File structure](/docs/en/file-structure.md) * [Working with tasks and watchers](/docs/en/tasks-and-watchers.md) * [TARS Options](/docs/en/options.md) * [Plugins configuration](/docs/en/plugins-options.md) * [Html](/docs/en/html-processing.md) * [Css](/docs/en/css-processing.md) * [Js](/docs/en/js-processing.md) * [Working with images](/docs/en/images-processing.md) * [Working with fonts and misc-files](/docs/en/fonts-and-misc.md) * [Usage script (scenarios)](/docs/en/scenarios.md) * [Upgrade guide](/docs/en/update-guide.md) * [FAQ](/docs/en/faq.md) ## Installation **Attention, [TARS-CLI](https://github.com/tars/tars-cli) is the preferred way to work with TARS. It is faster and more comfortable to work with TARS-CLI. In case of using TARS with TARS-CLI all installation steps are not necessary!** You need to [install `Node.js`](http://nodejs.org/) with version equal to 4.x.x and higher. If you use Node.js version 5.x.x, please, make sure, that you use npm version 3.x.x and higher. Otherwise update npm by using command: ```bash npm i -g npm ``` For Windows you have to do some more steps: * navigate to C:\Program Files (x86)\nodejs or C:\Program Files\nodejs via cmd.exe or any available terminal. The path depends on how Node.js was installed; * run command `npm install npm@latest`. If you get a **Permission denied** or **Error: EACCES** error, you should run the previous command again in sudo (as Administrator for Windows). Next you need to install gulp globally. (You may need rights of superuser or administrator). ```shell npm install -g gulp ``` [Download TARS](../../../tars/archive/master.zip) and unzip it in the working directory. Then install dependencies. Command is run from a folder with TARS files (usually it is a tars-master). ```shell npm install ``` If not all of the dependencies have been installed, the last operation must be repeated. After installing of all dependencies you need to open tars-config (detailed description of the options are [here](/docs/en/options.md)) and set up the project for yourself. In that config file, you can select the templater, css-preprocessor, using the notifications, folder names for different static and etc. After setting up the project, execute the following command: ```shell gulp init ``` **Attention, [TARS-CLI](https://github.com/tars/tars-cli) is the preferred way to work with TARS. It is faster and more comfortable to work with TARS-CLI. [Init command is available in TARS-CLI too](https://github.com/tars/tars-cli/blob/master/docs/en/commands.md#tars-init).** This command will create the basic file structure, download tasks for selected templater and css-preprocessor. Everything is ready, get to work! :) ## Basic commands **Attention, [TARS-CLI](https://github.com/tars/tars-cli) is the preferred way to work with TARS. It is faster and more comfortable to work with TARS-CLI. All commands are available and [described in TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/en/commands.md), so use only TARS-CLI for working with your project. TARS used Gulp to start tasks, when CLI was not created.** `gulp init` — initializes project with the specified settings in the tars-config. Creates a file structure. `gulp re-init` — **This command is deprecated!** reinitialize the project with specified settings in the tars-config. It is advised to use this command if you initialize the project with incorrect options. **Attention, files from pages and static folder will be deleted.** `gulp` or `gulp build` — build project. Non-minimized files are used by default. Build type depends on command parameters. Available parameters: * `--min` – minimized files are connected to html. * `--release` – minimized files are connected to html whose names have hash. This mode is useful if you are trying to directly deploy ready markup to the server. `gulp dev` — initialize of builder in development mode. Dev-version of the project is created without any minifications. It also launches watchers for project files. Available parameters: * `--lr` – initialize livereload (live page reloads with changes in project files), if it is included in the configuration of the project. * `--tunnel` – initialize project with markup sharing to the external web. The link will be shown in the console. There also will be a link to the control panel for devices to which markup is shared. `gulp build-dev` — generation of dev-version of the project without watchers. These parameters are available in any mode of assembly: * `--ie8` – to include in the build styles for ie8. * `--ie9` – to include in the build styles for ie9. * `--ie` – to include in the build styles for ie8 and ie9. ## Documentation It is important! All examples in documentation use the default settings. * [File structure](/docs/en/file-structure.md) * [Working with tasks and watchers](/docs/en/tasks-and-watchers.md) * [TARS Options](/docs/en/options.md) * [Plugins configuration](/docs/en/plugins-options.md) * [Html](/docs/en/html-processing.md) * [Css](/docs/en/css-processing.md) * [Js](/docs/en/js-processing.md) * [Working with images](/docs/en/images-processing.md) * [Working with fonts and misc-files](/docs/en/fonts-and-misc.md) * [Usage script (scenarios)](/docs/en/scenarios.md) * [Upgrade guide](/docs/en/update-guide.md) * [FAQ](/docs/en/faq.md) ## Last changes All recent changes are available here: [changelog](/docs/en/changelog.md). If you have a question you can write in [gitter](https://gitter.im/tars/tars?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) or mail [tars.builder@gmail.com](mailto:tars.builder@gmail.com) Bugs and feature-request here: [issues](https://github.com/tars/tars/issues/new). [downloads-image]: http://img.shields.io/npm/dm/tars-cli.svg?style=flat-square [npm-url]: https://npmjs.org/package/tars-cli ================================================ FILE: README_RU.md ================================================

English description | Описание на русском

# Ищем Maintainer'ов # ![Tars](https://raw.githubusercontent.com/artem-malko/artwork/master/tars/logo.png) [![Downloads][downloads-image]][npm-url] [![Mac/Linux Build Status](https://img.shields.io/travis/tars/tars/master.svg?label=Mac%20OSX%20%26%20Linux&style=flat-square)](https://travis-ci.org/tars/tars) [![Windows Build status](https://img.shields.io/appveyor/ci/artem-malko/tars/master.svg?label=Windows&style=flat-square)](https://ci.appveyor.com/project/artem-malko/tars/branch/master) [![Gitter](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg?style=flat-square)](https://gitter.im/tars/tars?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) TARS — сборщик frontend'а любой сложности, основанный на [Gulp](http://gulpjs.com/). Облегчает и ускоряет процесс разработки веб-сайтов/приложений, делая работу приятной и продуктивной. Подойдет как командам, так и отдельному разработчику. TARS решает большинство рутинных дел, связанных с веб-разработкой, чтобы вы получали больше удовольствия от работы. TARS — сборщик-фреймворк, включающий в себя набор gulp-тасков, предоставляющий возможность легкого расширения (создания новых тасков) и модифицирования уже существующих, предоставляет удобную архитектуру хранения тасков и вотчеров в проекте. Для того, чтобы не скачивать и не ставить все пакеты для TARS каждый раз, был создан [TARS-CLI](https://github.com/tars/tars-cli). Сам TARS — не npm-пакет. Такое решение было принято, чтобы каждый мог максимально комфортно кастомизировать сборщик под себя. CLI — просто удобный интерфейс над сборщиком, который содержит в себе все зависимости для TARS. **Желательно пользоваться именно CLI-версией для разработки.** Вы можете установить TARS-CLI через npm. Больше информации в [репозитории проекта](https://github.com/tars/tars-cli). **Обратите внимание, документация, которая находится в ветке «master» соответствует последней версии TARS. Если у вас используется другая версия, прошу открыть соответствующий релиз и смотреть документацию там! Кроме того, в корневой папке вашего проекта всегда есть папка с документацией, которая на 100% подходит к используемой версии TARS!** ## Основные фичи Ниже перечислена только малая часть особенностей, на самом деле их гораздо больше) * [Jade](http://jade-lang.com/), [Pug](https://pugjs.org/api/getting-started.html) или [Handlebars](http://handlebarsjs.com/) на выбор в качестве html-шаблонизатора. Также можно использовать обычный html. Подробности [здесь](/docs/ru/html-processing.md). * [Webpack](https://webpack.github.io) (вместе с [Hot Module Replacing](https://webpack.github.io/docs/hot-module-replacement.html)) или простая конкатинация JavaScript-кода в один файл. * Использование json (а точнее js-объекта, который может быть описан в json) для передачи данных в шаблоны (опционально, но очень крутая штука, которая позволит избавиться от копипаста). Подробнее [тут](/docs/ru/html-processing.md#%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-%D0%BC%D0%BE%D0%B4%D1%83%D0%BB%D1%8F%D0%BC%D0%B8-%D0%B8-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%BC%D0%B8-%D0%B2-handlebars). * [CLI-утилита](https://github.com/tars/tars-cli) и **автообновление проекта**. * Вы можете ипользовать ES6 (и некоторые фичи из ES7) уже сегодня. Подробнее в [документации](/docs/ru/js-processing.md). * [SCSS (SASS)](http://sass-lang.com/), [LESS](http://www.lesscss.org/) или [Stylus](http://learnboost.github.io/stylus/) в качестве препроцессора для css. Также в комплекте идет небольшой набор миксинов. Доступны sourcemaps. При выборе scss в качестве препроцессора, вы можете использовать как расширение scss, так и sass + можете миксовать их использование. Подробности [здесь](/docs/ru/css-processing.md). В комплекте идет [PostCSS](https://github.com/postcss/postcss) с [autoprefixer'ом](https://github.com/postcss/autoprefixer). Также очень [легко подключить дополнительные плагины для PostCSS](/docs/ru/options.md#postcss). * Никаких внешних библиотек и плагинов (кроме [html5shiv](https://ru.wikipedia.org/wiki/Html5_Shiv)). И да, это фича, так как вы вольны сами выбирать, какие библиотеки использовать. Доступны sourcemaps для JavaScript. * Используется модуль [chokidar](https://github.com/paulmillr/chokidar) для вотчинга файлов. * Расшариванием верстки с вашего компьютера во внешний веб, опционально. Ну и конечно же livereload в браузере (и не только локально) + графический интерфейс к панели управления устройствами, на которые расшаривается верстка. * [Можно легко добавлять новые таски и вотчеры](/docs/ru/tasks-and-watchers.md). Есть примеры того, как создать и использовать новый таск или вотчер внутри TARS. Это позволяет действительно легко интегрировать TARS в ваш проект или таски из вашего проекта в TARS. * Умная работа с изображениями. В первую очередь с вектором (svg). Больше не будет ада при верстке сайтов для экранов с высокой плотностью пикселей. Для работы с SVG поддерживаются два подхода: [SVG-спрайты](docs/en/svg-processing.md#svg-спрайты) и [SVG-symbols](docs/ru/svg-processing.md#svg-symbols). * Несколько режимов сборки (обычная, с минифицированными файлами, с хешем в названии css- и js-файлов для выкладки в продакшн). * Создание архива с готовой сборкой. В 2015 году я выступал с докладом о TARS на конференции DUMP. Можно ознакомиться с [видео с выступления](http://www.youtube.com/watch?v=JZ3thYdmQ3E&index=2&list=PLRdS-n5seLRrvvG0yU3uoYPKQDXvVW2nn), на котором рассказывается об одной из первых версий TARS, но оно все еще актуально. ## Документация Важно! Все примеры в документации используют настройки по умолчанию. * [Файловая структура](/docs/ru/file-structure.md) * [Работа с тасками и вотчерами](/docs/ru/tasks-and-watchers.md) * [Опции TARS](/docs/ru/options.md) * [Конфигурирование плагинов](/docs/ru/plugins-options.md) * [Html](/docs/ru/html-processing.md) * [Css](/docs/ru/css-processing.md) * [Js](/docs/ru/js-processing.md) * [Работа с изображениями](/docs/ru/images-processing.md) * [Работа со шрифтами и misc-файлами](/docs/ru/fonts-and-misc.md) * [Сценарии использования](/docs/ru/scenarios.md) * [Руководство по обновлению](/docs/ru/update-guide.md) * [Руководство для контрибуторов](/docs/ru/for-contributors.md) * [FAQ](/docs/ru/faq.md) ## Установка **Обращаем ваше внимание, что предпочтительно использовать [TARS-CLI](https://github.com/tars/tars-cli). Это удобнее, нагляднее, занимает меньше места. При работе с TARS через TARS-CLI, все дальнейшие шаги по установке не требуются!** Необходимо [установить `Node.js`](http://nodejs.org/) версии >= 4.x.x Если вы используете Node.js версии 5.x.x, убедитесь, что вы используете npm версии 3.x.x и выше. В противном случае обновите npm: ```bash npm i -g npm ``` Пользователям Windows необходимо выполнить еще пару шагов: * перейти в C:\Program Files (x86)\nodejs или C:\Program Files\nodejs в cmd.exe или в любом другом терминале. Путь зависит от того, куда Node.js был установлен; * запустите команду `npm install npm@latest`. Возможно потребуются права суперюзера. Далее необходимо установить gulp глобально. (Возможно потребуются права суперюзера или администратора) ```shell npm install -g gulp ``` [Скачайте TARS](../../../tars/archive/master.zip) и распакуйте в рабочую директорию у себя на компьютере. Затем устанавливаем зависимости. Команда запускается из папки с файлами TARS (обычно это tars-master). ```shell npm install ``` Если не все зависимости были установлены, то последнюю операцию нужно повторить. После установки всех зависимостей необходимо открыть tars-config (подробное описание опций [здесь](/docs/ru/options.md)) и настроить проект под себя. В конфиге вы можете выбрать шаблонизатор, css-препроцессор, использование уведомлений, имена папок для различной статики и т.д. После настройки проекта, выполняем следующую команду: ```shell gulp init ``` **Обращаем ваше внимание, что предпочтительно использовать [TARS-CLI](https://github.com/tars/tars-cli). [Команда инициализации доступна в TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/ru/commands.md#tars-init).** Данная команда создаст базовую файловую структуру, подтянет таски для выбранных вами шаблонизатора и css-препроцессора. Все готово, можно колбасить :) ## Основные команды **Обращаем ваше внимание, что предпочтительно использовать [TARS-CLI](https://github.com/tars/tars-cli). Это удобнее, нагляднее, занимает меньше места! Все команды, описанные ниже, [доступны в TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/ru/commands.md), используйте именно его для работы над проектом. TARS запускался через Gulp, когда не было CLI.** `gulp init` — Инициализирует проект с заданными опциями в tars-config. Создает файловую структуру. `gulp re-init` — **команда будет удалена в одном из следующих релизов** Переинициализирует проект с заданными опциями в tars-config. Предлагается использовать данную команду, если вы инициализировали проект с неверными опциями. **Внимание, при переинициализации все папки и файлы удаляются.** `gulp` или `gulp build` — делает сборку проекта. Подключаются не минимизированные файлы. Тип сборки зависит от переданных ключей вместе с этой командой. Доступные ключи: * `--min` – в html подключаются минимизированные файлы. * `--release` – в html подключаются минимизированные файлы, в названии которых есть hash. Данный режим полезен, если вы напрямую выкладываете верстку на сервер. `gulp dev` — инициализация сборщика в режиме разработки. Создается dev-версия проекта, без всех минификаций. Также запускает вотчеры за файлами проекта. Доступные ключи: * `--lr` – инициализация livereload (живая презагрузка страницы при изменениях в файлах проекта), если он включен в конфиге проекта. * `--tunnel` – инициализация проекта с расшариванием верстки во внешний веб. Ссылка будет указана в консоли. Также будет указана ссылка на панель управления устройствами, на которые расшарена верстка. `gulp build-dev` — генерация dev-версии проекта без вотчеров. Ключи, доступные при любом режиме сборки: * `--ie8` – включить в сборку стили для ie8. * `--ie9` – включить в сборку стили для ie9. * `--ie` – включить в сборку стили для ie9 и ie8. ## Документация Важно! Все примеры в документации используют настройки по умолчанию. * [Файловая структура](/docs/ru/file-structure.md) * [Работа с тасками и вотчерами](/docs/ru/tasks-and-watchers.md) * [Опции TARS](/docs/ru/options.md) * [Конфигурирование плагинов](/docs/ru/plugins-options.md) * [Html](/docs/ru/html-processing.md) * [Css](/docs/ru/css-processing.md) * [Js](/docs/ru/js-processing.md) * [Работа с изображениями](/docs/ru/images-processing.md) * [Работа со шрифтами и misc-файлами](/docs/ru/fonts-and-misc.md) * [Сценарии использования](/docs/ru/scenarios.md) * [Руководство по обновлению](/docs/ru/update-guide.md) * [Руководство для контрибуторов](/docs/ru/for-contributors.md) * [FAQ](/docs/ru/faq.md) ## Последние изменения Все последние изменения доступны по ссылке: [История изменений](/docs/ru/changelog.md). По всем вопросам можно писать в [gitter](https://gitter.im/tars/tars?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) или на почту [tars.builder@gmail.com](mailto:tars.builder@gmail.com) Баги и фича-реквесты сюда: [issues](https://github.com/tars/tars/issues/new). [downloads-image]: http://img.shields.io/npm/dm/tars-cli.svg?style=flat-square [npm-url]: https://npmjs.org/package/tars-cli ================================================ FILE: appveyor.yml ================================================ # AppVeyor file # http://www.appveyor.com/docs/appveyor-yml # Build version format version: '{build}' platform: - x64 - x86 clone_depth: 10 # Fix line endings on Windows init: - git config --global core.autocrlf true # What combinations to test environment: matrix: - nodejs_version: 16 install: - ps: Install-Product node $env:nodejs_version $env:platform - node --version - npm install -g npm - npm --version - npm install -g gulp - npm install build: off build_script: - gulp init test_script: - cmd: gulp build --release --ie ================================================ FILE: docs/en/changelog.md ================================================

English description | Описание на русском

# Changelog ## Version 1.9.9 * Fix bugs: #343 ## Version 1.9.8 * Dependencies update. * Fix bugs: #318,#324, #336, #325 ## Version 1.9.7 * Added webpack [ProvidePlugin](https://webpack.github.io/docs/list-of-plugins.html#provideplugin) support. This is optional, see [tars-config](https://github.com/tars/tars/blob/master/docs/en/options.md#provideplugin). ## Version 1.9.4 * Build won't be deleted in dev-mode. ## Version 1.9.2 * Fix bug with helper Icon in handlebars. ## Version 1.9.1 * Use gulp-pug-inheritance from fork because of errors in original. ## Version 1.9.0 * gulp-minify-html replaced with на gulp-htmlmin. * Add templater Pug support. * You can pass any data to templater by using env var TARS_ENV. * Bugfix. * English docs fixup and full update. Thanks to [icehaunter](https://github.com/icehaunter). * Dependencies update. ## Version 1.8.3 * Fix bug with svg2png in 2.0.0 Use 1.0.2 ## Version 1.8.2 * Fix watcher for templates with _ in the begining of the name; * Default scheme for Jade component has been changed. * Dependencies update. Eslint has been updated to version 3.x.x. ## Version 1.8.1 * Init process without user-package.json fixed. * Autoprefixer was added for IE9. * Pathes for IE entry points were fixed. * Dependencies update. ## Version 1.8.0 * Modules directory was renamed to components. This is optional, you can change it in [tars-config](options.md#componentsfoldername). * Task concat-modules-data was renamed to concat-mocks-data. * Log fixing for case, when there is problems with sprite generation. * You can configure gulp-plugins by using [plugins-config.js](plugins-options.md). * Jade recompilation became faster. * You can crate components inside another components. * All images from assets of component will be moved to static/img/assets. Images are files with extensions svg, png, jpg, jpeg, jpe, gif, tiff and bmp. Other files will be moved to static/components-assets. * staticPrefix was removed from tars-config. * Option [generateStaticPath](options.md#generatestaticpath) was added. * Build name is based on local date. * TARS works in NodeJs 6.x.x version. ## Version 1.7.1 * Rebuild process of jade-templates became faster. * Gulp-csso update to version 2.0.0. ## Version 1.7.0 * Plugin gulp-strip-debug has been deleted. uglifyJS will strip all useless code. * Error log became much more clear. * You can use notifier.success and notifier.error not in pipe only. * Tars-config has been updated. All JavaScript-options in [one object now](options.md#js). * You can [import style-files from node_modules/bower_components by using short syntax](css-processing.md). * [Webpack](https://webpack.github.io/) has been added. You can use old workflow (concatenation of files) or webpack — this is optional feature, you can manage it [from tars-config](options.md#workflow-1). Alse [Hot Module Replacing](https://webpack.github.io/docs/hot-module-replacement.html) is available. This feature is [managed from tars-config too](options.md#usehmr). * Tasks main:dev an js:processing have been updated. * .babelrc update. * .eslintrc update. New version of eslint is used. ```js // Updated/added rules: env: { commonjs: true }, parserOptions: { ecmaVersion: 6, sourceType: 'module' }, rules: { 'consistent-return': 0, 'keyword-spacing': 2, strict: 0, 'no-confusing-arrow': 2, 'prefer-arrow-callback': 0, 'no-debugger': 0 } // Deleted rules: 'no-arrow-condition': undefined, 'space-return-throw-case': undefined, 'space-after-keywords': undefined, 'no-empty-label': undefined, 'no-process-exit': undefined ``` * Documentation update. * Dependencies update. ## Version 1.6.3 * Bug with images minification has been fixed. * Taks minify-raster-img has been renamed to minify-images. SVG-images will be minified in that task. * Docs fixup. ## Version 1.6.2 * Icon helper has been renamed from icon to Icon * is helper has been updated. != and !== operation has been added. ## Version 1.6.1 * Fix tasks for content images copy process. ## Version 1.6.0 * Sourcemaps are created only in dev-mode. * Skipped tasks are highlighted in log of gulp. * There is only one task for css pre- and postporcessing for all preprocessors. * Stylies for IE9 are compiled in separate task. * Watchers became much more smarter. * There is only one task to work with templaters. * **TARS supports only Node.js 4.x.x and higher**. * Option for stylies-inject during livereload is [in tars-config now](options.md#injectchanges). * jscs + jshint has been replaced with eslint. * **[You can pass data of one module to another by using functions](html-processing.md#working-with-modules-and-data-handlebars). So, it is really easy to init module with any data.** * Great refactoring. - Add ES6, all tasks refactoring. - Build process starts much more fast. All dependencies are required only at that moment then they are really needed. - Some methods and helpers have been added: + skipTaskLog method — add info about skipped tasks into gulp log; + skipTaskWithEmptyPipe helper — it allows you to skip task, if no files were passed through that task; + root property — you can get absolute path to tars folder from this property. + isDevMode property — it returns !tars.flags.release && !tars.flags.min - There are only links to tasks in gulpfile. All main tasks (like build, dev) have been moved from gulpfile to tasks/main and to watchers. - Task browsersync has been removed. Browsersync starts in main:dev task. - Tasks svg-action and compile-html-with-data-reloading have been moved to watchers. - Task minify-html has been renamed to modify-html. - Task pre-build has been renamed and moved into namespace main (main:pre-build). * [You can use css-files, that won't be compiled to one file](css-processing.md). * All js-code from static folder is in ignore section in babelrc by default. Babel has been updated to version 6. * Page template and head module update. All useless attributes has been removed. Template looks like page in [html5boilerplate](https://github.com/h5bp/html5-boilerplate). * You can use %=static=% or \_\_static\_\_ in CSS and HTML instead of %=staticPrefixForCss=% and %=staticPrefix=%. Old prefixes are supported, but it is strongly recommended to use new prefixes. * staticPrefixForCss property has been removed from tars-config and it is generated in tars/tars.js automatically. * Normalize has been updated to version 3.0.3 * **[You can use custom Jade and Handlebars helpers](html-processing.md).** * Helper icon for Jade and Handlebars has been added to TARS. This helper generates template for svg-symbol including. * You can use [svg-symbols](svg-processing.md#svg-symbols). TARS supports three ways to include svg-symbols. Build for IE8 not supported in that workflow. And there is a polyfill in separate-js for svg-symbols correct loading for IE9 - Edge and all browsers, which don't support with flow. * useSVG property has been removed from tars-config. You have to configure SVG workflow by [new property in config](options.md#svg). In case of using old config (that has useSVG property), SVG config-object will be generated automatically. * [Data about all used pages will be add to full-data of your project](html-processing.md#html). * All sprite will have hash in their names then flag `--release` is used. * You can set port for Browsersync by using [env var](options.md#open). * [Default autoprefixer config has been updated](options.md#autoprefixerconfig). * Path to static folder generates automatically and depends on pages fs. * All useless tags, labels will be removed from build automatically. For example, if you don't build with `--ie` or `--ie8` flag, html5shiv won't be copied to ready build. * hml5shiv-print has been removed. * You can use plane JavaScript-object in data files. * [You can init your project without templater and preprocessor files mutation](https://github.com/tars/tars-cli/blob/master/docs/en/commands.md#tars-init). It would be useful for forks. * [You can automatically update your project with TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/en/commands.md#tars-update-project). * Task re-init is depricated now. This command will be removed from TARS in new version, cause there is great chance to broke your project. * Documentation update. ## Version 1.5.0 * Installation in NPM3 has been fixed. If you have a project, which has been made with TARS 1.4.1 and NPM2, and you want to develop this project in NPM3, you have to fix one line in tars/tars.js ```javascript handlebars: tars.require('gulp-compile-handlebars/node_modules/handlebars'), // replace with handlebars: tars.require('handlebars'), ``` * Handlebars is used from its own package, not from gulp-handlebars. * You can use css-files in etc folder. ## Version 1.4.1 * Verbose logs on Error in css will be in output. * Docs about [Babel using](js-processing.md) were updated. * Html-prettify config was updated. * Notification will appear on Error even all notifications has been disabled. * Deps have been updated, bugs have been fixed. ## Version 1.4.0 * Css imports were added. Css (less, scss, sass, styl) files, began with _ will not be compiled, so it is recommended to import only these files. [More info](css-processing.md). * Added .sass extension supporting. * Tars-config.js has been updated. [Sourcemaps](options.md#sourcemaps) has more options. Added [Babel supporting switcher](options.md#usebabel). * Added ES6(ES.Next) syntax supporting with [Babel](options.md#usebabel). [More info](js-processing.md). * Autoprefixer was moved to the end in the postprocessors list. * Notifier got one interface for failed and successed end of task. * gulp-html-prettify has been added. Formatted HTML will be generated if [minifyHtml](options.md#minifyhtml) is switched to false. * You need to use flags `--ie9` or `--ie` to compile stylies for IE9. `--ie` will compile stylies for IE8 and IE9 too. * More helpers were added, docs were updated for helpers and all helpers were moved to task-folder. * Some bugs have been fixed. ## Version 1.3.1 * Config for PostCSS has been fixed. You do not need to require packages by yourself. You just write them to config and it just works. But don't forget to install all used postprocessors locally via NPM. ## Version 1.3.0 * Sourcemaps for js was added. You can see file name and path to this file from sources in browser . * [PostCSS](https://github.com/postcss/postcss) has been added. You can [add all postprocessors what you want](options.md#postcss). * Notification is disabled while build process. You will see it only in that moment, when you will need it. * Added .hbs extension support for Handlebars templates. * Padding between images in raster-sprite has been added. * Main pages and modules have been refactored. * Browsersync will open default browser in OS, if there is no any [other instructions in tars-config](options.md#browser). * New entity tars has been added. This singleton has all methods and properties, which are useful for TARS. * [TARS-CLI has been created](https://github.com/tars/tars-cli). * Some bugs have been fixed. ## Version 1.2.7 * Bug with gulp-svg-spritesheet has been fixed. ## Version 1.2.6 * Bug with notify, when it is off has been fixed. ## Version 1.2.4 * Bug with init has been fixed. * Bug while png-sprite compiling has been fixed. ## Version 1.2.3 * Build process without notifier has been fixed. ## Version 1.2.2 * Assets' files watcher. Subdirectories are unsupported in modules/assets has been fixed. ## Version 1.2.1 * Code-style update. .jscsrc update. * Path was removed from dependencies list. * Docs in english were added. ## Version 1.2.0 * The new version of [Browsersync](https://www.browsersync.io/). * [baseDir](options.md#basedir) option for Browsersync was moved in tars-config. * Watchers use [chokidar](https://github.com/paulmillr/chokidar) module. * All watchers were moved in separate files in tars/watchers folder. * Watchers and tasks are included in gulpfile automatically. * 'builder-start-screen' task was moved into tars/tasks/services. * New helpers for handlebars were added (and [documentation for them](handlebars-helpers.md)). All helpers are stored in a separate file tars/helpers/handlebars-helpers.js * Framework folder was added on the path markup/static/js. This folder is for js-files used by the framework. * All dependences were updated. * Including modules syntax in Handlebars was changed. There is the old syntax: ```handlebars {{> modules/head/head head.defaults}} ``` And there is the new one: ```handlebars {{> head/head head.defaults}} ``` * There is no more a separate task to compile styles for IE9. Styles for IE9 are compiled as part of compiling styles task for all modern browsers. A separate file is created. * Workflow for preparing SVG was changed. Base64 encoding was changed with svg-sprite. Mixins for images including were not changed. * mData/mData.js –> data/data.js ## Version 1.1.1 * A bug of transfer js from separate-js was fixed. It was pointed out the old name of the folder. ## Version 1.1.0 * A user-package.json was added for user dependencies. There are changes in tars/helpers/install-additional-deps.js. * [Upgrade guide](update-guide.md) TARS was added. * [Gulp-sass](https://www.npmjs.com/package/gulp-sass) module was updated. * Generation version of the build was moved to a separate helper for easy customization. It is here: tars/helpers/set-build-version.js ================================================ FILE: docs/en/css-concat-processing.md ================================================

English description | Описание на русском

# CSS concat processing Concatenation of styles will be in the following order: * Normalize * Styles for libraries * Mixins, sprites * Fonts * Vars * GUI * Common stylies (common.scss) * Styles for plugins (static/scss/plugins, including all subdirectories) * Components' styles (css is supported) * Styles of etc.{scss,css} Also, you can use css files not including them into the bundle. There is a folder `separate-css` in `static/scss`, where you can store all files, which have to be included manually. There is an example of including in any template: ```handlebars ``` **%=staticPrefix=% prefix works, but this prefix is deprecated! Use just `%=static=%`!** ================================================ FILE: docs/en/css-manual-processing.md ================================================

English description | Описание на русском

# CSS manual processing This workflow will be usefull, if you need to control css processing by yourself. You can use manual css processing in TARS from version 1.8.0 Main entry points, style files which will contain imports for project style, are located at `static/scss/entry`. By default there will be one entry point created - `main.scss`. You can add more if you wil need it. These files will be compiled by a preprocessor. Your project files should be connected by adding them to entry point files via `@import` directive. `main.scss` entry point connection is already described in templates (`components/head`). In case you add new entry points, you need to connect them in templates by hand. `main.css` contents: ```scss @import '../normalize.scss'; /* Libraries, which is used in current project. */ @import 'partials/_libraries.scss'; /* Libraries, which is used in current project. */ @import 'built-in-partials/_service.scss'; /* Plugins, which is used in current project. */ @import 'partials/_plugins.scss'; /* Components, which is used in current project. */ @import 'partials/_components.scss'; /* Additional style files. */ @import '../etc/etc.scss'; ``` Entry point imports `normalize.scss`, then partial, where you can import libraries, then build-in partials (mixins for graphics, etc.), then partial with plugins, partial with components and lastly additional styles. Partial with components means that you will import your components' styles into that file specifically. But you don't need to use full relative path to compontnts' style from your partial. You can do like this: ```scss @import 'components/_template/_template.scss'; ``` Including styles for plugins and libraries from `node_modules` and `bower_components` is described in [general style documentation](css-processing.md). **Warning:** Do not edit files in `build-in-partials` directory as they can be overwritten on project update. Also there is an `ie` directory in entry points, which contains entry points for ie8 (files should have `_ie8` suffix) and ie9 (files should have `_ie9` suffix). Take note that only ie8 and ie9 specific styles should be included there, general styles will be added by default. ================================================ FILE: docs/en/css-processing.md ================================================

English description | Описание на русском

# CSS You can use folowing CSS-preprocessors: * [Scss](http://sass-lang.com) .sass extension is supported; * [Less](http://www.lesscss.org); * [Stylus](http://learnboost.github.io/stylus) You can choose CSS-preprocessor in [tars-config.js](options.md#csspreprocessor). In general, there are no surprises when using CSS-preprocessor. Use all the possibilities offered by the selected tool. If you are used to the usual CSS, you can use CSS-syntax in any preprocessor. TARS supports two workflows for CSS-code processing: * [css concatenation](css-concat-processing.md); * [css manual processing](css-manual-processing.md). All info below is general for both workflows. Все, что описано ниже справедливо для обоих подходов. All files with a `_` prefix won't be compiled by the builder. You should use these files for imports. Actually, you can import any files you want, but if you import a file without `_` you will have two copies in the compiled CSS file. This is the reason why files with `_` prefix won't be compiled. You can import all types of style files: `scss` (`sass`), `less`, `styl`, `css`. Example of import using `scss`: ```scss // files are located in one directory @import '_partial.scss'; // _partial.sass is located in neighbour directory `partials` @import '../partials/_partial.sass'; ``` If you need to include files from `node_modules` or `bower_components`, you don't have to write full path to `node_modules`, you can use short syntax, TARS will expand the path like this: ```scss @import 'bootstrap/dist/bootstrap.scss'; ``` In case of that import TARS will try to find `bootstrap/dist/bootstrap.scss` in `node_modules` and `bower_components`. This feature is implemented in TARS from version 1.7.0 If you want to include the files from the static directory (pictures), you should use the placeholder %=static=%. Then including of the image as a background (in current example the picture will be taken from your main component) will be as follows (in this example scss is used): ```scss .main { background: url('%=static=%assets/main/bg.png') repeat; } ``` **%=staticPrefixForCss=% prefix works, but this prefix is deprecated! Use just `%=static=%`! This prefix works in TARS from version 1.6.0** There are a couple of points on the organization of `scss|sass|less|styl` files (e.g scss is selected): * Each component has its own css-representation. * Common styles for the project are recommended to put in common.scss in static/scss * Fonts are included in `fonts.scss` * Mixins are in `mixins.scss` * UI-elements styles are in `GUI.scss` * Variables are in `vars.scss` * Libraries styles are in `static/scss/libraries` (may contains subfolders and css-files). * Styles for plugins are in `static/scss/plugins` (may contains subfolders and css-files). * Styles which can't be put under categories listed above have to be put in `static/scss/etc/etc.{scss,css}`. * In the main folder with css (in this case, scss folder) you can not create new files (except when you correct task by yourself connected with working with css). New files can be created only in the `static/scss/plugins|libraries|etc|separate-css`. If you'd like to use library from bower or npm package, you can import styles from package by using `@import`. For IE8 and IE9 you can add fixes in a folder in the ie component folder. You need to create `ie8.{scss,sass,css}` or `ie9.{scss,sass,css}`. ================================================ FILE: docs/en/faq.md ================================================

English description | Описание на русском

# FAQ For all questions I am waiting for you in the [gitter](https://gitter.im/tars/tars?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) or by email [tars.builder@gmail.com](mailto:tars.builder@gmail.com). 1. **I have webpack and npm-scripts, so, I do not understand, how TARS with Gulp will be useful for me?** Every task has its own instrument to resolve it. NPM-scripts are really good for many tasks and you can use only NPM-scripts. But Gulp is not only task-runner actually, it allows you easy transform file from FS to Stream. In case of using NPM-scripts, you have to develop parallel and async tasks processing. And some words about webpack: it was created to resolve imports/exports/requires in JavaScript. Nowadays it has quite many plugins, but its main task is to compile JavaScript. And in the end, Gulp + webpack = love, they can (and should) work together. You can get more info from comments of [docs for webpack with Gulp usage](http://webpack.github.io/docs/usage-with-gulp.html). 2. **Why Gulp, and not Grunt?** Gulp is a stream builder of JavaScript projects. It uses streams and it is really fast. For example, I have a project where about a thousand stylus files, Grunt needs about 2.5 seconds for assembly and 2 seconds for processing by autoprefixer. Gulp makes all stuff for 0.5 seconds winning Grunt at least 4 times. 3. **How to work with TARS?** There are several variants. * You have one big project with long period of develop/support. TARS will be extremely useful for you. Create components, pages. Store it somewhere in GIT, SVN. * You have many projects with general components. So, in taht case you have several options: - you can create you own library of components and include in to your own fork of TARS. So you will have all used components after init; - you can use git. Every new project is a new branch from master. Inited TARS in master branch; - and the last, you can store your own library of used components somewhere. * You have many different projects. Just use CVS (GIT, SVN, etc.). You can choose any option or create your own workflow. 4. **We have our own builder on Gulp/Grunt, but we'd like to work with TARS and use features from our builder.** You can transfer your tasks to user-tasks in TARS. If you would like to transfer grunt-tasks, you have to rewirte them to Gulp or use [gulp-grunt](https://www.npmjs.com/package/gulp-grunt). If you need to Init TARS with all user-tasks by default you should create your own fork of TARS and init TARS with link to your fork. You can get more info from [docs for TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/en/commands.md#tars-init). 5. **I have OS X (Ubuntu, Linux Mint …). Not all project's files are in the build.** You have to increase the [ulimit](options.md#ulimit) in tars-config.js 6. **I don't know anything about Gulp. Can I use this builder?** Knowledge of working with Gulp is not required. At the moment, builder covers most tasks of frontend. All you need to know is described in the documentation. 7. **It seems to me that you are using is too complex file structure. Can I modify it for myself?** If you know how to work with Gulp, after renaming/deleting/creating folders, you must edit appropriate tasks or [create user-tasks](tasks.md). Some directories are not mandatory and they can be safely removed. You can also easily expand the file structure for js using the appropriate [options](options.md#jspathstoconcatbeforemodulesjs-%D0%B8-jspathstoconcataftermodulesjs) in the builder config file. For the main folder with statics and folders whith images you can set the name in respective [options](options.md#fs) in the builder config file. 8. **Everything seems to be installed, but nothing works. What to do? I have a Windows (7, 8, 10)** Probably not all dependences were installed. Run `npm i` command again. If you still have errors, it would be nice if you will send them to ([tars.builder@gmail.com](mailto:tars.builder@gmail.com)) or to [gitter](https://gitter.im/tars/tars?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) chat. ================================================ FILE: docs/en/file-structure.md ================================================

English description | Описание на русском

# File structure **File structure is generated automatically. You do not need to create anything yourself.** Builder has the following file structure: ``` ├── gulpfile.js # gulpfile of builder ├── tars.json # System file with info about builder ├── tars-config.js # Config file ├── package.json # Basic dependencies ├── .babelrc # Config for Babel ├── .eslintrc # Config for eslint ├── user-package.json # User dependencies └── tars/ # Tasks and helpers for gulp └── helpers/ # Helpers └── tasks/ # System tasks └── user-tasks/ # User's tasks └── watchers/ # System watchers └── user-watchers/ # User's watchers └── tars.js # Main file of the builder └── markup/ # The main project folder └── components/ # Components └── pages/ # Page's templates └── static/ # Static-files (css, js and so on) └── docs/ # Documentation ``` ## The structure of the individual component Component is an independent unit of the page. Example component - "header" or "footer". Each page consists of components. Any component may include other components and can be included into each other. ``` exampleComponent/ # Component example └── assets/ # Static files for current component (files with any extension) Subdirectories unsupport └── ie/ # Styles for IE9.scss|sass|less|styl и IE8.scss|sass|less|styl) └── data/ # Folder for component's data ├── data.js # Data for component (there is an example for data in _template component) ├── exampleComponent.html # Handlebars-represention of component (it could be jade) ├── exampleComponent.scss|less|styl # Css-representation of component (scss|sass|less|styl) ├── exampleComponent.js # Js-represent ├── anotherComponentFolder ``` Any component can be can be embedded into another component. All images from asstes will be moved to static/img/assets/component_name or static/img/assets/component_name/embedded_component_name, if current component is embedded into another. Images are files with extensions svg, png, jpg, jpeg, jpe, gif, tiff and bmp. Other files will be moved to components-assets (the name of folder is depend on option fs.componentsFolderName). The basic idea is to make the component as much isolated structure as possible. You can use the [BEM](https://ru.bem.info), [web components](http://webcomponents.org) (and their [realization from Google](https://www.polymer-project.org)), something else. You can do everything by old-fashioned way, all markup is in one component, but it is not recommended. If we talk in BEM terms, each component is a block. There is an [excellent lecture](https://www.youtube.com/watch?v=pyAYbbDJjPo) on how to organize your code. Page templates are in `pages` folder. Pages are layouts and should contain as little code as possible. To create a new page just copy the existing one (or _template) and rename it or run [tars add-page](https://github.com/tars/tars-cli/blob/master/docs/en/commands.md#tars-add-page-pagename). Also, you can add components via TARS-CLI — [tars add-component](https://github.com/tars/tars-cli/blob/master/docs/en/commands.md#tars-add-module-modulename). ## Folder structure for static files We assume that Scss was chosen as a css-preprocessor. ``` static/ # Folder for static-files. You can choose the name for that folder in tars-config.js └── fonts/ # Fonts (can contain subdirectories) └── img/ # Images. You can choose the name for that folder in tars-config.js └── content/ # Images for content (can contain subdirectories) └── plugins/ # Images for plugins (can contain subdirectories) └── general/ # General images for project (can contain subdirectories) └── sprite/ # Raster images, which is included in png-sprite. └── 96dpi/ # Images for displays with dpi 96 ... └── 384dpi/ # Images for displays with dpi 384 (more info in images-processing) └── svg/ # SVG-images └── js/ # js └── framework/ # js-frameworks (backbone, for example) └── libraries/ # js-libraries (jquery, for-example) └── plugins/ # js-plugins └── separate-js/ # js-files, which must not be included in ready bundle └── misc/ # General files, which will be moved to root directory of ready project — favicons, robots.txt and so on (can contain subdirectories) └── scss ├── entry/ # Styles for entry points for css in case of manual css-processing More info [here](css-manual-processing.md). └── etc/ # Styles, which will be included at the end of the ready css-file (can contain subdirectories) └── libraries/ # Styles for libraries (can contain subdirectories) └── plugins/ # Styles for plugins (can contain subdirectories) └── sprite-generator-templates/ # Templates for sprite generating └── sprites-scss/ # Mixins for sprites ├── separate-css/ # Css-files, which must not be included in ready bundle ├── common.scss # General styles ├── fonts.scss # Styles for fonts ├── GUI.scss # Styles for GUI elements (inputs, buttons and so on) ├── mixins.scss # Project's mixins ├── normalize.scss # Styles reset ├── vars.scss # Variables ``` ## The structure of the complete build There will be two folders in the root after assembly of the project: dev and builds. Below is the description of the dev version (with --ie8 mode enabled). The finished build is not much different from the dev version. ``` dev/ └── static/ # Folder for static-files. You can choose the name for that folder in tars-config.js └── css/ # Ready styles and styles for IE9 and IE8, if support is turned on and styles from separate-css. └── components-assets/ # Static files for components. └── exampleComponent/ └── img/ # Images for project └── assets/ # Static files for components. Only images └── exampleComponent/ └── content/ # Images for content └── plugins/ # Images for plugins └── svg-sprite/ # SVG-sprite └── png-sprite/ # PNG-sprite for different dpi └── rastered-svg-images/ # Raster svg-images for IE8 └── minified-svg/ # Minifies svg-images └── js/ # Ready main.js and separate js-files └── separate-js/ └── temp/ # Temp folder for components' data ├── Ready pages and misc-files ``` Build version of the project does not contain a temp folder, includes minified css and js files. It contains optimized pictures and an archive with the assembled project (optional). If the option useBuildVersioning is enabled, each build will be in a separate folder on the path that is specified in the option [buildPath](options.md#buildpath), called build_ver%build_date%. If useBuildVersioning disabled, the finished project will be generated on the path that is specified in the option buildPath, in folder 'build'. When you need to include an image you have to use the path in which they exist in the build. Immediately after initialization or reinitialization, `.tmpPreproc` and `.tmpTemplater` folders can appear in the root folder, which contain a downloaded template and css-preprocessor. After the first build these folders will be deleted. So just ignore them. These folders are included in .gitignore, so they won't be in your repository. This file structure can be changed with the appropriate corrections of tasks and watchers. For some folders you do not need to dig through tasks and watchers: for example, it is possible to create a folder for storing js, [which must be included before and after the components](options.md#jspathstoconcatbeforemodulesjs-и-jspathstoconcataftermodulesjs). This will be useful in case of using different js-frameworks. Also, it is not necessary to use all the folders for images or JavaScript. If something is not necessary, it can be removed. ================================================ FILE: docs/en/fonts-and-misc.md ================================================

English description | Описание на русском

# Working with fonts and misc-files All fonts are in the fonts folder with statics for the project. In misc folder you can store any additional files, such as favicon and so on. All files will be copied from here into the root of the compiled project. Supports nested directories. When you copy files folder hierarchy will be saved. ================================================ FILE: docs/en/handlebars-helpers.md ================================================

English description | Описание на русском

# Handlebars-helpers There are some useful built-in helpers. You can add your own helpers to `/tars/user-tasks/html/helpers/handlebars-helpers`. It is not necessary to register your helpers. You just have to add them to exported object `handlebarsHelpers` as a function. All custom helpers will be available in tempalates automatically. Besides, all custom helpers will be moved automatically after project update via TARS-CLI. Let's describe built-in helpers. ## repeat It is used to create a simple loop from 0 to n. Syntax: ```handlebars {{#repeat n}} Do something {{/repeat}} ``` n — is a number of repetitions. Number, integer. ## is It is used to expand the standard `if`. Standart `if` is able to check only if a value exists or not. `is` allows you to use the default behavior of if from JavaScript. The comparison operation is passed as a string as the second argument. The comparison values are passed as a string (or as a value from data) as the first and the third arguments. Following operations are available (all operations are performed in JavaScript, respectively, and the comparison result is obtained in the same way as if it were inside JavaScript): * `==` not strict equality; * `===` strict equality; * `>` strict greater; * `>=` greater or equal; * `<` strict less; * `<=` less or equal; * `!=` not strict inequality; * `!==` strict inequality. `test` is the variable passed to the template. ```js testComponent: { test: 10 } ``` Syntax: ```handlebars {{#is test '>' 9}} true {{else}} false {{/is}} ``` ## strip It cuts all spaces from the passed content. Syntax: ```handlebars {{#strip}} {{/strip}} ``` Result: ```html ``` ## toLowerCase Transform passed string to lowercase. Syntax: ```handlebars {{toLowerCase 'string'}} ``` ## toUpperCase Transform passed string to uppercase. Syntax: ```handlebars {{toUpperCase 'string'}} ``` ## capitalizeFirst Transform of the first character of passed string to uppercase. Syntax: ```handlebars {{capitalizeFirst 'string'}} ``` ## formatDate, now, i18n Additional helpers. Docs are [here](https://github.com/assemble/handlebars-helpers) ================================================ FILE: docs/en/html-processing.md ================================================

English description | Описание на русском

# HTML [Jade](http://jade-lang.com), [Pug](https://pugjs.org/api/getting-started.html) or [Handlebars](http://handlebarsjs.com) can be used as a html templater. You can choose templater in [tars-config.js](options.md#templater) or [during initialization of TARS via TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/en/commands.md#tars-init). You can use all features of Jade, Pug and Handlebars. If you are used to the regular HTML, choose the handlebars and write HTML as before. If you don't want to compile a particular page, you can simply add the '_' at the begining of the page name and it will not be compiled. If you need to include files from the static directory (images, js-files), you must use the placeholder [`%=static=%` or `__static__`](options.md#staticprefix). Then including of an image will be as in following example (in this example Handlebars is used): ```html ``` To include image in CSS you need to use the same placeholder – `%=static=%`. This placeholder will be replaced with string from [staticprefixforcss](options.md#staticprefixforcss) from config. **%=staticPrefixForCss=% and %=staticPrefix=% prefixes work, but these prefixes are deprecated! Just use %=static=%! New prefixes work in TARS from version 1.6.0** Very important feature is the usage of different data types in one template. For example, we have a head component, which has all that you should put in the head tag (different meta, titles, etc.). Suppose that every page should have its own title. Making copies of the same component, which differ only in one line is not the best practice. It would be logical to separate data from presentation. So, the folder with the component has a folder called `data`, which has js file with data for this component. Example of data can be found in the component _template: ```js componentName: { dataType: { property: value } } ``` In case of syntax errors in data files from your editor you can use another syntax, just a simple JavaScript object: ```javascript data = { componentName: { dataType: { property: value } } }; ``` TARS supports both syntaxes by default. In the file `data.js` comments are supported within the data object. You can add component into another component folder from TARS 1.8.0. In that case there can be some problems with duplicating names of these components. To prevent this situation, TARS generates unique key for each embedded component using the next scheme: ```javascript 'parentComponentName_anotherParentComponent_currentComponentName' = { dataType: { property: value } }; ``` In the embedded component data file you can write code as usual: ```javascript const data = { 'currentComponentName': { dataType: { property: value } } }; ``` Unique key will be generated automatically. By default full data will contain the data from `_template` component and a list of all project pages like this: ```javascript __pages: [ { name: 'pageName', href: 'pageHref' } ] ``` You can use this array to render a list of links to all pages of a project. You can pass any data to templater by using env var TARS_ENV. For example, you can pass a simple string: ```bash TARS_ENV="Hello World" tars dev --silent ``` And then you can get it in template (handlebars): ```handlebars {{TARS_ENV}} ``` You can pass object to TARS_ENV too: ```bash TARS_ENV="{\"name\": \"Paul\"}" tars dev --silent ``` And then you can get it in template (handlebars): ```handlebars {{TARS_ENV.name}} ``` **It is important to add double quotes and escape quotes inside object!** Connecting components with different data looks differently in Jade/Pug and Handlebars. ## Working with components and data in Handlebars Including component on the page: ```handlebars {{> componentFolderName/componentName}} ``` Including component with passing data to the template: ```handlebars {{> componentFolderName/componentName componentName.dataType}} ``` Example of including head component with default data: ```handlebars {{> head/head head.defaults}} ``` Inside the component data is displayed by the handlebars: ```handlebars {{title}} ``` If you include component without passing data, component gets an access to the global scope. For example, if we include component `head` without data, we will have to use the following code to get access to the field `title`: ```javascript // head/data/data.js head: { defaults: { title: 'Default title' } } ``` index.html ```handlebars {{> head/head}} ``` head.html ```handlebars {{head.defaults.title}} ``` But, if you have passed the data to component, you will not have access to the data of a child component. You have to pass global scope to the parent component (to not pass any data while including), to pass data for a child component. Or you can use another variant: index.html ```handlebars {{> component1/component1 component1.main}} ``` component1.html ```handlebars

{{title}}

{{> component2/component2 component2.main}} ``` ```javascript // component1/data/data.js component1: { main: { title: 'Title of component1', component2: function (fullData) { return fullData.component2; } } } ``` component2.html ```handlebars

{{title}}

``` ```javascript // component2/data/data.js component2: { main: { title: 'Title of component2' } } ``` So, you can get access to data of any component from data-file of current-component by using really simple construct: ```javascript // component/data/data.js component: { main: { title: 'Title of component', innerComponentData: function (fullData) { // fullData is an object // with all data of the application return fullData.componentName.componentType; } } } ``` Everything will be much more easier with arrow functions ES6: ```javascript // component/data/data.js component: { main: { title: 'Title of component', innerComponentData: fullData => fullData.componentName.componentType } } } ``` Do not forget, that embeded components will have unique key in the complete data file in the build. Handlebars is known as a very simple templater. But it is uncomfortable to use Handlebars in creation process without frameworks or something like that. So, different helpers have been added that expand Handlebars. Helpers description can be found [here](handlebars-helpers.md). ## Working with components and data in Jade/Pug When using Jade/Pug, each component is a mixin, which is included in a page file. Mixin can receive data. Including component on the page: ```jade include ../components/componentFolderName/componentName +componentName() // Component include ``` Including component with data transmission in the template: ```jade include ../components/componentFolderName/componentName +componentName(componentName.dataType) // Component include ``` Example of head component including with default data: ```jade include ../components/head/head +head(head.defaults) ``` You have to add extension in Pug: ```jade include ../components/head/head.pug +head(head.defaults) ``` Inside the component data is displayed by Jade/Pug (for example, the head component): ```jade mixin head(data) #{data.title} ``` You can use any features that are available in Jade/Pug. You can include components with any nesting of child components and with any data by using inlude and '+'. And you can use functions in data.js like in examples for Handlebars. There is one built-in helper for Jade/Pug in TARS — Icon. This helper generates templates for svg symbol inclusion. You can add your own helpers to `/tars/user-tasks/html/helpers/jade"pug-helpers`. There is an example of user-helper in there. You can use added helpers in a template like: For Jade: ```jade = jadeHelpers.helperName(params) != jadeHelpers.helperName(params) ``` For Pug: ```jade = pugHelpers.helperName(params) != pugHelpers.helperName(params) ``` ================================================ FILE: docs/en/images-processing.md ================================================

English description | Описание на русском

# Images All work with images in TARS can be divided into two parts: "Sprites" and "Separate images". ## Sprites TARS supports two formats for a sprite image: PNG and SVG. **TARS supports two workflows of working with SVG. You can get more info from [docs about working with SVG](./svg-processing.md)** The general approach is described in the [presentation](http://www.slideshare.net/codefest/codefest-2014-2) of web developer [Timofey Chaptykov](https://github.com/Chaptykov). Approach is briefly described below. The advantage of this approach is explained in the presentation and will not be explained here. Advantages of concatinating interface (and other small or often repeated images) into a single sprite will not be described here. If you don't know what a sprite is, you can look up the details [here](https://en.wikipedia.org/wiki/Sprite_(computer_graphics)). You may skip the theory and go to the [description of the work with sprites](#sprites-inclusion). Nowadays there are a lot of displays with different pixel density. So, what does it mean? Let's compare iPhone 3GS and iPhone 4. 3GS has 320x480 display resolution and iPhone 4 has 640x960. How can you see, resolution has doubled, but diagonal is the same. It means, that pixel became smaller. So, there is a parameter device-pixel-ratio (or dppx) which means, how many real pixels there are in one logical pixel. For iPhone 4 dppx is 2. More details can be found [here](http://stackoverflow.com/questions/21971331/what-is-dots-per-css-inch-and-dots-per-physical-inch) and [here](http://www.w3.org/TR/css3-values/#absolute-lengths). Suppose we have a sprite of PNG images. These pictures have a fixed size. If we will stretch this image on the number of pixels 3 times the size of the image, the image will be blurry. To get rid of this problem, you can use an image 3 times larger for such display, and the size of the image in CSS must be set basing on the size of the original image (the property background-size). At the moment there are screens with dppx from 1 to 4 (and soon will be higher). To prepare sprites for the 4 screen sizes is a lot of work. SVG helps. SVG is vector, it does not depend on dppx of the screen, it is rendered perfectly in modern (and not so) browsers. You can make only 1 size and this image will look the same on all screens. Unfortunately SVG has several disadvantages: * SVG badly displays radial and other complex gradients (linear is displayed excellently). * Complex shadows are badly displayed. * Is not displayed in IE8. So we have to combine two approaches: SVG everywhere we can use it. For the rest - prepare PNG images for those screens that you are going to support. For IE8 we will simply rasterize SVG images. **TARS supports two workflows of working with SVG. You can get more info from [docs about working with SVG](svg-processing.md)** ## Sprites inclusion Images that can not be rendered in SVG are copied to 'static/img/sprite/96dpi|192dpi|288dpi|384dpi'. 96dpi folder is for images for screens with dppx = 1, 192dpi folder is for images twice as large as the original, with the names of the originals. These images will be displayed on the screens with dppx = 2. And it's similar for other dppx. Used screens are configured [in the tars-config](options.md#useimagesfordisplaywithdpi). Including icon from raster sprite to CSS code is achieved by a mixins (example on SCSS, mixins name and other input parameters for different CSS-preprocessors are the same): ```scss @include bg($png-image-name); // Sprite with png-images inclusion ``` Attention, $png-image-name is a **variable**, that has the same name as the icon, which you'd like to use (without extension). `bg` mixin will include background into the CSS, picture size, background-size and sets positioning inside png sprite. It is not necessary to add nothing more, mixin will set media expression for screens with different dppx. ## Separate images Working with separate images is very simple. Separate images are divided into several categories. Depending on the category images are placed in different locations. Builder supports images of any type, but only SVG, PNG, JPG will be exposed to minification. _Anything described below is just a recommendation, you can structure image storage however you like._ ### Images for component They are located in the assets folder inside the component. To include image using the following template (to connect images to HTML you must use the placeholder [`%=static=% `](options.md#staticprefixforcss)): ```css .componentName { background: url('%=static=%assets/componentName/sample-image-name.png') no-repeat; } ``` If you would like to insert images in HTML, you have to use the placeholder [`%=static=%`](options.md#staticprefix): ```handlebars
``` **%=staticPrefixForCss=% and %=staticPrefix=% prefix works, but these prefixes are deprecated! Use just `%=static=%`! New prefix works in TARS from version 1.6.0** Nested directories are supported. ### Images for content They are in the folder (by default): `static/img/content/`. You should put images that you will use in the content area on the site into this folder, for example, on the news page. Nested directories are supported. Including images inside HTML: ```handlebars
``` **%=staticPrefix=% prefix works, but this prefix is depricated! Use just `%=static=%`!** ### Images for plugins They are in the folder (by default): `static/img/plugins/`. In this folder you should put images that are used in different plugins. Nested directories are supported. ### General images They are in the folder (by default): `static/img/general/`. In this folder you should put images that are used for the whole project, such as the general background of the site. Nested directories are supported. ================================================ FILE: docs/en/js-concat-processing.md ================================================

English description | Описание на русском

# JS-processing with simple concatenation You should use this workflow in case if you don't have large project or you don't need to resolve dependencies between files. All JavaScript files will be concatenated into one file in a specific order. By default JavaScript files are located in 2 places: * in the static folder, in a subfolder named `js`; * in each separate component. You can add your own folders for JavaScript, using the appropriate [option](options.md#jspathstoconcatbeforemodulesjs-and-jspathstoconcataftermodulesjs) in the TARS config file. All JavaScript-code is collected in a separate file, except for JavaScript files, which are located in a `separate-js` directory. These files are copied as-is in the build. Example of such file is `html5shiv.js`. Files are collected in the following order: * `static/js/framework` (including subfolders) * `static/js/libraries` (including subfolders) * `static/js/plugins` (including subfolders) * all files, which have paths in the `jsPathsToConcatBeforeModulesJs` option * JavaScript-files from components * all files, which have paths in the `jsPathsToConcatAfterModulesJs` option **All files with `_` in the begining of the file name won't be added to bundle and won't be linted by eslint.** Checking files from `jsPathsToConcatBeforeModulesJs` and `jsPathsToConcatAfterModulesJs` can be controlled separately by [appropriate options](options.md#jspathstoconcatbeforemodulesjs-and-jspathstoconcataftermodulesjs). ================================================ FILE: docs/en/js-processing.md ================================================

English description | Описание на русском

# JS-processing TARS supports two workflows for JavaScript-code processing: * [concatenation of all JavaScript-files into one bundle in a specific order](js-concat-processing.md); * [resolving dependencies between JavaScript-files (from TARS 1.7.0)](js-webpack-processing.md). Both workflows support style and error checking with eslint. Config files for eslint are in the root folder: `.eslintrc` and `.eslintignore`. You can switch off eslint by using [`js.lint` config option in `tars-config.js`](options.md#lint) ES6 (ES.Next) syntax is supported by using [Babel](https://babeljs.io/). Use option [`useBabel`](options.md#usebabel) to turn on the ES6 (ES.Next) syntax (it is turned off by default). If you want to exclude some files from Babel processing you can add `babel_ignore_` to the begining of file name or add the file (or directory) to ignore in `.babelrc` in the project root. All JavaScript files from folders `static/framework`, `static/libraries`, `static/plugins` and `static/separate-js` are ignored in `.babelrs` by default. All config for Babel is in the project root. See [all babel options](https://babeljs.io/docs/usage/options/), except for sourcemap and filename which is handled for you. You can manage sourcemaps from [options](options.md#sourcemaps). ================================================ FILE: docs/en/js-webpack-processing.md ================================================

English description | Описание на русском

# JS-processing with webpack **Please, direct all questions about "how webpack works"/"how to configure webpack" to Google, Stack Overflow and so on!** If you do not know anything about webpack, please, read [documentation of webpack](http://webpack.github.io/docs/) at first. Webpack is already configured in TARS for comfortable work. But you can change `webpack.config.js` in the project root as you need. By default, there is only one entry point: `markup/static/js/main.js`. You can choose another entry point or points. **You have to use function `prepareEntryPoints` to prepare config object with entry points. It is necessary for Hot Module Replacement!** By default webpack can resolve dependencies, which is required by `require` (`import/export`, if babel is used). You can require JavaScript file of any component in any JavaScript file of your project by using alias `components`. Let's assume, that we are in `markup/static/js/main.js` and we'd like to require JavaScript file from component `example`. You can set relative path, but it is to difficult to calculate the correct path. So we can use alias `components`: ```js import foo from 'components/example/example'; // useBabel: true // or const foo = require('components/example/example'); // Old type will work too const foo = require('modules/example/example'); ``` Also, there is alias for static folder: ```js import $ from 'static/js/jquery/jquery'; // useBabel: true // or const $ = require('static/js/jquery/jquery'); ``` If you need to require module from `node_modules`, you should specify package name only: ```js import $ from 'jquery'; // useBabel: true // or const $ = require('jquery'); ``` Sourcemaps are already configured and you can [manage them from tars-config](options.md#sourcemaps). Sourcemaps from vendor modules will be added to main sourcemaps by source-map-loader. uglifyJS is used to compress production-ready code. You can use value of `NODE_ENV` in your code. [webpack.DefinePlugin](http://webpack.github.io/docs/list-of-plugins.html#defineplugin) is used. Webpack built-in watcher is used for changes in your code. Also, you can use [Hot module replacement](https://webpack.github.io/docs/hot-module-replacement.html). This feature is implemented with middleware for Browser-sync and plugin [webpack.HotModuleReplacementPlugin](http://webpack.github.io/docs/list-of-plugins.html#hotmodulereplacementplugin). By defult you can use babel to transpile your ESNext code into ES5. Babel-loader is used. Also, you can lint your code by eslint. Eslint-loader is used for this feature. Eslint uses built-in JavaScript code parser, but if you need to lint ESNext code, you have to use another parser: babel-eslint. So, you have to install it localy and set it in .eslintrc. You can get more info from [babel-eslint repository](https://github.com/babel/babel-eslint) and [documentation for eslint](http://eslint.org/docs/user-guide/configuring#specifying-parser-options). ================================================ FILE: docs/en/options.md ================================================

English description | Описание на русском

# Options All builder configuration is in one file — `tars-config.js` at the root of the project. You need to restart the build to apply changes. ## Variable options ### postcss Type: `Array` Default: `[]` Example: ````javascript postcss: [ { name: 'postcss-short', options: { deny: ['text'] } }, { name: 'postcss-size', options: {} } ] ```` You can set all used postprocessors. Do not forget to install them. ### svg Type: `Object` Config for working with SVG in TARS. #### active Type: `Boolean` Default: `true` Activate svg-processing. #### workflow Type: `String` Default: `sprite` Available workflows of working with SVG in TARS. You can use SVG-sprite `sprite` and SVG-symbols `symbols`. **Build for IE8 won't be created then "symbols" is used** #### symbolsConfig Type: `Object` Config for working with SVG then "symbols" workflow is selected. ##### loadingType Type: `String` Default: `inject` This option sets type of svg-symbols loading workflow. You can set: * inject into the page code — `inject`; * just separate file — `separate-file`; * separate file with link for each use to that file — `separate-file-with-link`. ##### usePolyfillForExternalSymbols Type: `Boolean` Default: `true` SVG-symbols loading from separate file is supported in all modern browsers natively except IE9 - Edge. You have to use polyfill for them. If you do not support IE, you can set false to this option. ##### pathToExternalSymbolsFile Type: `String` Default: `''` You can set a path to file with svg-symbols. File will be created in that directory, which was set in option. It will be created in the root of your build by default. Possible value: `static/images/`. ### css Type: `Object` Config for CSS processing in TARS. #### workflow Type: `String` Default: `concat` Type of CSS-code processing. You can set: * `concat` — concatenation of all CSS-files into one bundle in a specific order; * `manual` — you have to import all used files into entry points by yourself. ### js Type: `Object` Config for JavaScript processing in TARS. #### workflow Type: `String` Default: `concat` Type of JavaScript-code processing. You can set: * `concat` — concatenation of all JavaScript files into one bundle in specific order; * `modular` — using bundler, which will resolve all dependencies between JavaScript-files. #### bundler Type: `String` Default: `webpack` You can specify bundler, if `modular` workflow is selected. Right now you can only choose webpack. #### lint Type: `Boolean` Default: `true` Error checking in JavaScript code and code style (config for eslint is in the project root, in `.eslintrc`. See [eslint options](http://eslint.org/)). Also, you can manually switch off linting of files and folders by using `.eslintignore` in the root of your project. #### useBabel Type: `Boolean` Default: `false` This option allow to use [Babel](https://babeljs.io/) for ES6(ES7) syntax support. Config for Babel is in project root, in `.babelrc`. See [babel options](https://babeljs.io/docs/usage/options/), except for `sourcemaps` and `filename` which are handled for you by default. #### webpack Type: `Object` You can switch on/off additional cool features for webpack. ##### useHMR Type: `Boolean` Default: `false` Switch on/off [Hot module replacement](https://webpack.github.io/docs/hot-module-replacement.html). ##### providePlugin Type: `Object` Default: `{}` [Provide Plugin](https://webpack.github.io/docs/list-of-plugins.html#provideplugin) options. Automatically loaded modules. #### removeConsoleLog Type: `Boolean` Default: `true` Removing console.log and alerts from js files in the build. It's an option, because sometimes it is necessary to retain console.log in the complete build. #### jsPathsToConcatBeforeModulesJs and jsPathsToConcatAfterModulesJs Type: `Array of Strings` Default: `[]` This option makes sense only in case of using concat workflow. In that case all JavaScript code of the project is concatenated into one file except for JavaScript files located in the `separate-js` directory. If you want to include files from other locations into the build (for example, you created a separate directory for JavaScript files), you can register it in these options by adding a path or an array of paths (patterns paths, such as `controllers/**/*.js`) to JavaScript files. Files, which should be added to the build before main modules should be added in `jsPathsToConcatBeforeModulesJs` and after main modules in `jsPathsToConcatAfterModulesJs` It will be useful for building a website on a JavaScript framework, which adds its own entities (such as controller, router, etc.). You do not need to go into tasks, just create a separate directory and specify for which files you want to watch. Also you can disable eslint for these files (lintJsCodeBeforeModules and lintJsCodeAfterModules options). ### sourcemaps Type: `Object` Default: ```javascript sourcemaps: { js: { active: true, inline: true }, css: { active: true, inline: true } }, ``` Config for sourcemaps. Sourcemaps for JavaScript and CSS work only in dev mode. active {Boolean}: to use sourcemap or not. inline {Boolean}: to use sourcemap inlined into source-file or to use a separate file. ### notifyConfig Config for notifications module. When project files are changed there will be given a system notifications, which will indicate which file is changed and what task is executed. #### useNotify Type: `Boolean` Default: `true` Enabling of notification. You can disable notifications by using environment variables: ```bash export DISABLE_NOTIFIER=true; # or export NODE_ENV=production; ``` Environment variables will overwrite useNotify value from tars-config.js #### title Type: `String` Default: `'TARS notification'` Each notification has a title. If you want to see another title, you should change this option. #### sounds Sounds during the notifications. ##### onSuccess Type: `String, undefined` Default: `undefined` In this option the name of the system sound is passed which will be played during the notification in case of a successful build. If you don't need the sounds, you can set it with `undefined` value. ##### onError Type: `String, undefined` Default: `undefined` In this option the name of the system sound is passed which will be played during the notification in case of a failed build. If you don't need the sounds, you can set it with `undefined` value. ### minifyHtml Type: `Boolean` Default: `false` Enabling minifications for HTML. If is set to `false`, compiled html will be prettified. ### generateStaticPath Type: `Boolean` Default: `true` This option turns on autogeneration of a relative path to the static directory from the current page. In case of using a server or livereload, path to static won't be generated, because static files are served by the server. ### devPath Type: `String` Default: `'./dev/'` You can set a string with a relative or an absolute path to the folder where the project should be built in development mode. Using `/` after the path name is required so that there are no problems accessing the files. ### buildPath Type: `String` Default: `'./builds/'` You can set a string with a relative or an absolute path to the folder where the project should be built. If you are using useBuildVersioning (use versioning of builds), each new build will be created in a separate folder with a name - the build version, and each folder will be created at the path specified in `buildPath`. Using `/` after the path name is required so that there are no problems accessing the files. ### useBuildVersioning Type: `Boolean` Default: `true` Use build versioning. The name of the version consists of the build name + date of creation (accurate to a second). ### useArchiver Type: `Boolean` Default: `true` Creating the archive of the build. The archive is created in the folder with the build. If project name is set in `package.json`, it will be used as the archive name, otherwise it will be `build` by default. The date of build creation will be also added to the name of the archive. ### ulimit Type: `Number` Default: `4096` By default, the number of simultaneously open files in the operating system (unix based) is limited. Since the TARS is working on Gulp, the number of simultaneously open files may be large. To avoid problems with that, you can set [ulimit](http://ss64.com/bash/ulimit.html). If the project uses the large number of files and some of them do not get into the final build, then you can just increase this option. ## Partially modifiable options These options can be changed before the command `init` only, because they don't influence any other command, besides `useImagesForDisplayWithDpi`. More info below. ### templater Type: `String` Default: `handlebars` Options: `jade`, `pug`, `handlebars` Used templater is specified in this option. `Jade`, `pug` and `handlebars` are available for now. The name of the templater is set in the option with a small letter. If you want to write in plain HTML, retain the option unchanged. ### cssPreprocessor Type: `String` Default: `scss` Options: `scss`, `sass`, `less`, `stylus` Used css preprocessor is specified in this option. ### useImagesForDisplayWithDpi Type: `Array` Default: `[96]` The pixel density of different screens, which will be supported by your project. Supported values are: * 96 - 1 dppx (usual display) * 192 - 2 dppx (retina display) * 288 - 3 dppx (for example, nexus 5) * 384 - 4 dppx (for example, nexus 6) On the basis of this option, a folder for png images of different sizes for different screens is created. Read more in [images processing](images-processing.md) docs. This option can be changed at any time, but there is a couple of important points. If this option is changed after `gulp|tars init`, it is necessary to create (or delete) directories in the `static/img/sprite/` folder by hand. The format of the folder name - option value + dpi. For example, `192dpi`. ### fs Options for main folders with static naming. If you change the option from this block after `gulp|tars init` or `gulp|tars re-init`, it is necessary to rename the appropriate directories by hand. #### staticFolderName Type: `String` Default: `'static'` The name of the folder where static files of the the project will be. If you are developing a project locally, it is necessary that the value of this option matches with the value of [staticPrefix (deprecated)](#staticprefix) option. #### imagesFolderName Type: `String` Default: `'img'` The name of the folder where images of the project will be. Usually this folder has different names, so setting it is optional. #### componentsFolderName Type: `String` Default: `'components'` The name of the folder where components (modules for TARS 1.7.0 and below) of the the project will be. ## Deprecated ### useSVG **Option is deprecated! Use [`svg.active`](#active)** Type: `Boolean` Default: `true` Enabling svg-image support. ### staticPrefixForCss **Option is deprecated! Value is set in `tars/tars.js`** Type: `String` Default: `../imageFolderName/` Custom path to the folder with the static for css files. imageFolderName is taken from the [imagesfoldername](options.md#imagesFolderName) option. ### useJsLintAndHint **Option has been renamed to [`lint`](#lint) and moved to js config object.** ### autoprefixerConfig Configuration for autoprefixer ([read more here](https://github.com/postcss/autoprefixer#autoprefixer-)). In short, this module allows you not to write vendor prefixes. In this configuration you do not need to include IE8 and IE9, style assembly is done by another way for them . You can look [here](https://github.com/postcss/autoprefixer#browsers) which browsers are available. If you do not want to use autoprefixer, pass `false` in this option. ~~**Option was moved to plugins-config.json.**~~ **Option was moved to .browserslistrc.** ### browserSyncConfig Config for the Browsersync module. This module implements the possibility livereload in browser, sharing the markup to an external web, creating a local server. #### baseDir #### port #### open #### browser #### startUrl #### useNotifyInBrowser #### injectChanges **Options were moved to plugins-config.json. You can set any [option, which is supported by browsersync](https://www.browsersync.io/docs/options/).** ### staticPrefix The value of this option sets the value of the placeholder %=static=% or __static__, which can be used in any project files. %=staticPrefix=% prefix works, but this prefix is deprecated! Use just %=static=% or __static__! **Option is deprecated! Value is set in tars/tars.js** ================================================ FILE: docs/en/plugins-options.md ================================================

English description | Описание на русском

# Plugins configuration Since TARS 1.8.0 you can configure most plugins (gulp plugins and more) in a separate file `plugins-config.json` in the project root. Before you had to override task using the plugin or even modify the builder files. You can change all options, but it is **strongly recommended** to leave some options as default, because TARS depends on them to function correctly. All such options are described in comments in `plugins-config.json`. `plugins-config.json` is not just a simple json file. You can use commnets and special expression insert(). You can use it to execute JavaScript code inside this json file. For example, `gulp-jade` need option `basedir`, where we can set path to partials. So, we can set it manually and change every time than we decide to change name of components dir. insert() allows us to do it automatically. ```js "gulp-jade": { "pretty": true, "basedir": "markup/insert(tars.config.fs.componentsFolderName)" } ``` In that case `insert(tars.config.fs.componentsFolderName)` will be replaced with value of `fs.componentsFolderName` from `tars-config.js`. So, that code will be interpreted like: ```js "gulp-jade": { "pretty": true, "basedir": "markup/components" } ``` You can execute any JavaScript code by insert. Some more examples: ```js "example-plugin": { "option": "insert(function() {return 'tars'})" } ``` insert(function() {return 'tars'}) will be replaced with: ```js "example-plugin": { "option": "tars" } ``` ================================================ FILE: docs/en/scenarios.md ================================================

English description | Описание на русском

# Usage scenarios There are 3 scenarios of using TARS. In fact, you can up with another scenarios. The main scenarios will be listed here: * development with a transfer to the back-end for implementing; * development of a static site locally. * development of a static site that is ready to deploy. You can get more info from [FAQ](faq.md). In all scenarios, it is mean that the development mode (dev-task) will be available with any keys. ## Development with a transfer to the back-end developer In this case, in the tars-config is important to set the minifyHtml option to false. You can also disable removeConsoleLog (false), to retain all console.log unchanged. In tars-config, in the devPath option, it is also possible to specify a new path for integration with the back-end part of the project. So, for the convenience of builds versioning you can include the useBuildVersioning and useArchiver options, to have the archive ready for sending in each folder with built project. During assembly (build-task) is desirable not to use the `-–release` key. To verify efficiency of minified files can be used the `-–min` key. ## Development of a static site locally In this case, the minifyHtml option can be any way you want. All other options you can set as comfortable except useArchiver. This option should be turned off because we don't need useless files. During assembly (build-task) is desirable to use the `--release` key. ## Development of a static site that is immediately ready for deploy All the same, as for the "Development of a static site locally." During assembly (build-task) you have to use the `--release` key. ================================================ FILE: docs/en/svg-processing.md ================================================

English description | Описание на русском

# Working with SVG TARS supports two workflows for working with vector graphic: SVG-sprite and SVG-symbols. There are exist some more workflwos (inline SVG in HTML, inline in CSS, base64 in CSS, SVG-stack), but SVG-sprite and SVG-symbols is the best choice at the moment, cause they totally are supported by all browsers (from IE9). That workflows are really fast and it is comfortable to work with them. You cannot use symbols and SVG-sprite in one time. All options for working with SVG is set in tars-config. **It is important that when you save the image in SVG there is have to be viewBox attribute! Save SVG as an object that can be inserted into HTML without changing (in Adobe Illustrator Image location option — Embed).** ## SVG symbols **Build for IE8 not supported in that workflow** In that workflow SVG-images will be combined into one SVG-file and every iscon will be represented as [SVG-symbol](https://developer.mozilla.org/ru/docs/Web/SVG/Element/symbol). You can reuse each icon, set colors and size from CSS in that case. You can get more info from [css-tricks](https://css-tricks.com/svg-symbol-good-choice-icons/). Images that will be included in such way must be in a folder (default path): 'static/img/svg/'. Nested directories are **not** supported. Symbols are created to use it in tempaltes (html|jade|hbs). In CSS you can change colors, size, add stroke and stroke width. You sholud use helpers for symbols using in templates and components. Helper creates HTML, add size's attributes and custom classname. Using in handlebars: ```handlebars {{Icon iconName='iconName' className='customClass' iconWidth='25' iconHeight='25'}} ``` Using in jade: ```jade != jadeHelpers.Icon.call(locals, {iconName: 'iconName', className: 'customClass', iconWidth: '25', iconHeight: '25'}) ``` Using in pug: ```jade != pugHelpers.Icon.call(locals, {iconName: 'iconName', className: 'customClass', iconWidth: '25', iconHeight: '25'}) ``` You can set two properites: iconname (iconName), which you'd like to include (without extension), classname for that icon (customClass), sizes (iconWidth, iconHeight). **Sizes are not required, so you can drop it from helper options**. TARS generate class automatically by using template icon__iconName in case you have not passed it to helper. TARS use sizes from svg file if you not passed it to helper. You can use that helper in pages and components too. That helper will generate HTML like: ```html ``` File with ready symbols is generated by TARS automatically. It only remains to connect it. TARS supports several ways to include SVG-symbols: * **inject** — inject into the page code; * **separate-file-with-link** — separate file with link from each use to that file; * **separate-file** — just separate file. In inject case only Icon ID (its name) will be set in symbol use tag. You can manage, where you'd like to inject all symbols by using label %=symbols=%. **It is not necessary to remove that labels and scripts from tempaltes, cause they will be deleted from build automatically, if they are not used!** In case of using separate file with link, path to SVG-symbols file and Icon ID will be passed into xlink:href. ```html ``` In that case SVG-symbols file will be cached in browser. You can set the path to file by using option pathToExternalSymbolsFile in tars-config. File will be generated in that directory. File will be created in the root directory of build by default. SVG-symbols loading from separate file is supported in all modern browsers natively except IE9 - Edge. You can use polyfill for them. You can exclude it from build by using option usePolyfillForExternalSymbols if you don't support IE. The code of polyfill including is in templates by default. **It is not necessary to remove that labels and scripts from tempaltes, cause they will be deleted from build automatically, if they are not used!** In the third one you have to implement your own workflow of SVG-symbols injecting to HTML. You have to write some code to load SVG-symbols file and inject it into the page-code. There are two useful articles, which describe the best ways to implement it: [css-tricks](https://css-tricks.com/ajaxing-svg-sprite/) and [osvaldas.info](http://osvaldas.info/caching-svg-sprite-in-localstorage). The last is the most cool. More info about symbols configuration you can get from [options docs](options.md#svg). ## SVG-sprites SVG images are combined into the SVG-sprite. SVG-images in the release-version is minified and has release hash in the name. Images that will be included in such way must be in a folder (default path): 'static/img/svg/'. Nested directories are **not** supported. You can include image by using mixin (example on scss): ```scss @include bg-svg($svg-image-name); // Sprite with svg-images including ``` Attention, $svg-image-name is a **var**, that has the same name as the icon, which you'd like to use (without extension). `bg-svg` mixin will include SVG-sprite as a background, will set all necessary offsets and sizes into the CSS. In case of `--ie` and `--ie8` flags using sprite of rastered SVG-images will be created for IE8 automatically. You can not set color of SVG icon from CSS. So, it is necessary to create production-ready icon, with correct size and color. ================================================ FILE: docs/en/tasks-and-watchers.md ================================================

English description | Описание на русском

# Tasks and watchers TARS is a set of gulp-tasks organized in a special way. Each task is a separate file (except for components files, such as build, dev, etc.), where you can describe transformations of a set of files. Also, where are watchers in TARS, which allow you to start tasks after any file of your project was changed. Tasks and watchers can be system (build in TARS by default) and user's. You can use it to add more features to TARS. In general, TARS works in developer mode as follows: * all tasks, which are used to build your project are started; * after build proccess all watchers will be started. They will watch for files in your project and start tasks after file change. All built-in tasks are in the `tars/tasks` directory. They are divided into folders according to the task type. built-in watchers are in the `tars/watchers` directory. You can add your own tasks and watchers in `tars/user-tasks` and `tars/user-watchers`. When you add tasks or watchers it is recommended to use: * tars.config.fs.staticFolderName - for the name of the folder with statics; * tars.config.fs.imagesFolderName - for the name of the folder with images; * tars.templater.ext - contains an extensions for files of the selected templater; * tars.cssPreproc.ext - contains an extensions for files of the selected css-preprocessor. If you need to replace built-in task/watcher, you have to call you own task/watcher like it's built-in. Do not forget to repeat file structure. There is small example, which is true for tasks and watchers: let's imagine, that there is a built-in task `minify-html.js`: ``` tars/tasks/html/minify-html.js ``` And you need to use your own `minify-html.js`. So, you have to create folder `html` inside `user-tasks` and create file `minify-html.js` there (repeat file structure of built-in task and use the same name of a task): ``` tars/user-tasks/html/minify-html.js ``` In that case only user's task will be included in gulpfile.js over the default one. If you need to include your own task into an existing task chain, for example into the dev task, you have to override main:dev task by your custom version of it with the chain that will useful for you. Also, you can switch off any task/watcher by adding `_` sign at the begginng of the name of that task/watcher. You can get more info in docs for [tasks](tasks.md) and [watchers](watchers.md). ================================================ FILE: docs/en/tasks.md ================================================

English description | Описание на русском

# Tasks Each task is a [CommonJS-module](http://wiki.commonjs.org/wiki/Modules/1.1). All tasks are automatically included in gulpfile. You can create your own tasks in the `user-tasks` directory. By default, only links for main tasks are included in gulpfile.js. For example, `build` is a link to `main:build`. So, you can override any task in TARS quite easily. You can create your own tasks in `user-tasks` directory. There is an example task included by default. Generally, you could connect any gulp-task to TARS. By default, each task requires a set of npm-modules and configs to work correctly: ```javascript const gulp = tars.packages.gulp; const gutil = tars.packages.gutil; const notifier = tars.helpers.notifier; ``` Also, if you want to use livereload for this task, you must to connect browserSync module: ```javascript const browserSync = tars.packages.browserSync; ``` If you require any dependences, include them here. You can add dependencies, which are not in the main `package.json`, you can add to the `user-package.json`, which is at the root of the project. The format is the same as in the main package.json **Do not put your own dependencies in package.json. Put them into user-package.json** There is only one exception — initialization via TARS-CLI. `user-package.json` won't be created when you init your project via TARS-CLI with common archive with TARS (from current repository). Also, you can [init TARS with TARS-CLI and your own zip archive with TARS](https://github.com/tars/tars-cli#tars-init). If you need to use some additional packages and initialize project via TARS-CLI, you have to add them to user-package.json in your own TARS fork and all additional packages will end up in package.json of new project automatically after `tars init`. This feature is supported from version 1.1.8 of TARS-CLI. After dependency connection goes the body of a module, which will export the task. Each task is described in an exported function. You have access to global variable `tars` in all tasks and watchers. You can get any info about your current project (config, used prepocessor and so on) from that variable. Exported function returns the complete gulp-task. After that you can deal with it as with usual task for gulp. If you need notification, your task must be ended as follows: ```javascript // If you need to reload browser, uncomment the row below // .pipe(browserSync.reload({stream:true})) .pipe( notifier('Example task is finished \n') ); ``` The string which is passed to notifier will be displayed in notifications You can also call the callback, or return the main thread, if you want to perform tasks in a certain order. Read more [here](http://frontender.info/handling-sync-tasks-with-gulp-js). ================================================ FILE: docs/en/update-guide.md ================================================

English description | Описание на русском

# TARS update guide **Automatic project-update is available via TARS-CLI and TARS from version 1.5.0. You can get more info from [documentation of TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/en/update-actions.md). It is not necessary to do anything from this artcile in case of using TARS-CLI!** In one major version (for example, 1.\*.\* ), you can use a markup folder (this is the folder in which should be the sources of your project) in any version. In any version within one major version building will be successful. This is true for TARS above (and including) version 1.2.0. Prior to 1.2.0 there were small changes in the file structure and method of including components in the Handlebars. All changes are available in the [changelog](changelog.md). To get the new functionality, which was released in a new minor version (for example *.4.* ) is enough: * [download new TARS](https://github.com/tars/tars/archive/master.zip); * initialize it with the settings that are in your current project; * transfer the folder markup from the current project to a new TARS; * udpate tars-config, if it is necessary. After that, you can use the new features. Learn more about versioning system [here](http://semver.org/). **Automatic project-update is available via TARS-CLI and TARS from version 1.5.0. You can get more info from [documentation of TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/en/update-actions.md)!** There are some important moments. For example, work with coffee-files has been added in one of the minor versions. If your project uses only JavaScript, you can also use any minor version within the major. If you want to use the coffee-files, you need to select only the version in which tasks for working with them were added or higher version. In the [readme](../README.md) is described in which version you have access to the different functionality. Also, if you have changed builder files (anything else, except markup folder), it is necessary to apply these changes manually. All recent changes available in [changelog](changelog.md). ================================================ FILE: docs/en/watchers.md ================================================

English description | Описание на русском

# Watchers As tasks, watchers is a [CommonJS-module](http://wiki.commonjs.org/wiki/Modules/1.1). All watchers are automatically included in a gulpfile. You could create your own watcher in a `user-watchers` directory. By default, there is already an example of a watcher. Let's take a closer look. By default, each watcher requires a set of npm-modules and configs to work correctly: ```javascript const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const gutil = tars.packages.gutil; const chokidar = tars.packages.chokidar; const watcherLog = tars.helpers.watcherLog; ``` ```javascript return chokidar.watch( /* String of path pattern or array of strings */, Object.assign(tars.options.watch, { // Options set bellow will override default from tars.options.watch // If you need default options, you can use just tars.options.watch ignored: /* String of path pattern or array of strings to ignore. If nothing to igonre — just set it to ''*/, persistent: /* Boolean, true by default*/, ignoreInitial: /* Boolean, true by default*/ }) ).on('all', function(event, path) { watcherLog(event, path); // You could start as many tasks as you need runSequence(/* Task name (String) to start */); }); ``` You can pass a pattern or pattern arrays of path to files for which you need to watch into `chokidar.watch`. You can pass options for `chokidar` after patterns. If default options are ok for you, you can pass just `tars.options.watch` as the second argument of `chokidar.watch`. If you need to override some options, you have to use [`Object.assign`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign). You can pass a pattern or an array of patterns of paths to files that you want to filter from watching within current watcher into the option `ignored`. Task name is passed to `gulp.start`, which should be run on any changes in watched files. By default watchers work for all file operations (delete, create, rename). You can change this behavior by changing the `.on('all', function(event, path)` to the needed event. List of available events is in [chokidar docs](https://github.com/paulmillr/chokidar#getting-started). ================================================ FILE: docs/ru/changelog.md ================================================

English description | Описание на русском

# Changelog ## Version 1.9.9 * Исправлены: #343 ## Version 1.9.8 * Обновлены версии зависимых пакетов * Исправлены: #318,#324, #336, #325 ## Version 1.9.7 * Добавлена поддержка [ProvidePlugin](https://webpack.github.io/docs/list-of-plugins.html#provideplugin) у webpack. Настройка происходит в [конфиге](https://github.com/tars/tars/blob/master/docs/ru/options.md#provideplugin). ## Version 1.9.4 * Папка build не удаляется при запуске TARS в dev-режиме. ## Version 1.9.2 * Исправлен баг с работой хелпера Icon в handlebars. ## Version 1.9.1 * Переключились на gulp-pug-inheritance из форка, так как оригинал содержит ошибки. ## Version 1.9.0 * gulp-minify-html заменен на gulp-htmlmin. * Добавлена поддержка шаблонизатора Pug. * Добавлена возможность передачи любых данных в шаблоны с помощью переменной окружения. * Вычитана документация на английском языке, спасибо большое [icehaunter](https://github.com/icehaunter). * Исправлены баги. * Обновлена документация. * Обновены версии зависимостей. ## Version 1.8.3 * Пофикшен баг с svg2png. Испольузется 1.0.2 версия пакета. ## Version 1.8.2 * Вотчер за шаблонами стал умнее. * Для Jade используется свой шаблон по умолчанию для компонента. * Обновление зависимостей сборщика. Eslint обновлен до версии 3.x.x. ## Version 1.8.1 * Проект можно заинитить без user-package.json * Добавлен autoprefixer для IE9 в режиме ручной сборки стилей. * Поправлены пути до партиалов в точках входа для IE. * Обновление зависимостей сборщика. ## Version 1.8.0 * modules теперь называются components. При этом это название [конфигурируемо](options.md#componentsfoldername). Можете использовать modules как и раньше. * Таск concat-modules-data переименован в concat-mocks-data. * Исправлен лог ошибки при сборке спрайтов в случае, если иконка не найдена. * Появилась возможность задавать конфиг для используемых в TARS плагинов с помощью [plugins-config.js](plugins-options.md). * Ускорена пересборка Jade-шаблонов при изменении data-файлов. * При добавлении SVG и использовании symbols Jade-шаблоны теперь не пересобираются. Необходимо сохранять вручную шаблоны и страницы, на которых используется иконка. Такое решение принято, чтобы не нужно было каждый раз ждать полной пересборки всех шаблонов при добавлении иконки. Изменение касается только Jade. * Появилась возможность вкладывать компоненты друг в друга. * Изображения из assets компонентов хранятся в static/img/assets, остальные файлы из assets будут хранится в static/components-assets. К изображениям относятся файлы svg, png, jpg, jpeg, jpe, gif, tiff и bmp. * Опция staticPrefix удалена из конфига. Теперь она генерируется автоматом. * Добавлена опция [generateStaticPath](options.md#generatestaticpath), которая включает построение относительного пути от текущей страницы до папки со статикой. В случае использования сервера, который будет раздавать статику (например, режим livereload) путь до статики не будет генерироваться, так как статика раздается сервером. * Имя билда теперь генерируется, как в TARS 1.6.0 Используется локальное время. * TARS работает в NodeJs версии 6.x.x ## Version 1.7.1 * Значительно ускорена пересборка Jade-шаблонов. * Обновлена версия gulp-csso до второй версии. ## Version 1.7.0 * Удален плагин gulp-strip-debug. Теперь его работой занимается uglifyJS. * Обновлен вывод при ошибке. Он стал более понятный, сразу ясно, куда смотреть в логах. * notifier.success и notifier.error теперь можно использовать как в pipe, так и в обычных функциях. Сообщение об ошибке легко найти в консоли. * Обновлен состав конфига сборщика. Конфиг стал более компактным. * Появилась [возможность импортить стили из node_modules/bower_components](css-processing.md) не указывая полный путь до пакета, а использовать сокращенный путь. * Добавлен [webpack](https://webpack.github.io/) для сборки JavaScript. Также осталась возможность использовать старый workflow для работы с JavaScript — простая склейка файлов. Управление [workflow происходит в конфиге сборщика](options.md#workflow-1). Также есть возможность использовать [Hot Module Replacing](https://webpack.github.io/docs/hot-module-replacement.html). Эта фича опциональна, управляется из [конфига проекта](options.md#usehmr). * Обновлены таски main:dev и js:processing. Обратите внимание на них, если они переопределены в вашем проекте. * Обновлен .babelrc. * Обновлен .eslintrc, так как был произведен переход на вторую версию eslint. ```js // Обновленные/добавленные правила: env: { commonjs: true }, parserOptions: { ecmaVersion: 6, sourceType: 'module' }, rules: { 'consistent-return': 0, 'keyword-spacing': 2, strict: 0, 'no-confusing-arrow': 2, 'prefer-arrow-callback': 0, 'no-debugger': 0 } // Удаленные правила: 'no-arrow-condition': undefined, 'space-return-throw-case': undefined, 'space-after-keywords': undefined, 'no-empty-label': undefined, 'no-process-exit': undefined ``` * Обновлена документация. * Обновлены версии зависимостей. ## Version 1.6.3 * Поправлен баг с минификацей изображений в релизной сборке. До этого фикса минификация не происходила. * Таск minify-raster-img был переименован в minify-images. Теперь в нем еще минифицируются SVG-изображения, не являющиеся иконками. * Правки в документации по HTML-компиляции. ## Version 1.6.2 * Icon helper был переименован из icon в Icon. * В is helper были добавлены операции != и !==. ## Version 1.6.1 * Пофиксил таски для переноса контентных изображений. ## Version 1.6.0 * Sourcemaps создаются только в dev-режиме. * Пропущенные таски слегка подсвечиваются в общем логе Gulp. * Все таски для работы со стилями теперь общие для всех препроцессоров. Они больше не скачиваются и сразу находятся в TARS. * Стили для IE9 компилятся в отдельном таске. * Вотчеры за изменениями в стилях стали умнее. Теперь они будут вызывать только те таски, которые действительно нужны в данный момент. * Таски для компиляции HTML объединены в один. * **Убрана поддержка Node.js версии ниже 0.12.x включительно.** * Опция инжекта CSS при livereload [вынесена в tars-config.js](options.md#injectchanges). Если вам нужен инжект стилей при пересборке без перезагрузки страницы, то необходимо установить эту опцию в true. * jscs + jshint были заменены на eslint. Проверка кода проходит куда быстрее. Весь код TARS также подвергается проверке eslint перед каждым коммитом. * **[Появилась возможность пробрасывать данные одного модуля в данные другого с помощью функций в data.js](html-processing.md#Работа-с-модулями-и-данными-в-handlebars). Теперь стало легко инициализировать модули с вложенными модулями с любыми данными в Handlebars.** * Рефакторинг кода. - Были отрефакторены все таски. Используется ES6. - Ускорен запуск самой сборки. Теперь зависимости подключаются только в тот момент, когда таск запускается в первый раз. Первоначальная сборка в итоге занимает меньше времени. - Добавлены новые методы и свойства в tars.js: + метод skipTaskLog — выводит лог о пропущенных тасках с информацией о причинах пропуска; + хелпер skipTaskWithEmptyPipe — позволяет пропустить таск, если в pipe не было передано ни одного файла. + Свойство root — хранит путь от корня ОС до папки tars, включая саму папку. + Свойство isDevMode — возвращает результат выражения !tars.flags.release && !tars.flags.min - В gulpfile.js находятся только ссылки на таски. Это сделано с целью более легкой кастомизации TARS. Сами таски перенесены частично в tasks/main и в вотчеры. Подробности далее. - Удален таск browsersync. Browsersync включается внутри таска main:dev - Таски svg-action и compile-html-with-data-reloading перемещены в вотчеры напрямую, без создания доп. тасков. - Таск minify-html переименован в modify-html, так как в этом таске происходит не только минификация html, но и форматирование. - Таск pre-build переименован и перенесен в namespace main. * [Появилась возможность использовать css-файлы отдельно от общего бандла](css-processing.md). * Весь js-код из папки static по умолчанию находится в ignore в babelrc. Сам babel обновлен до 6 версии. Если вы хотите использовать самый последний TARS-CLI, в старых проектах необходимо поправить конфиг .babelrc, так как это сделано в текущей версии. По умолчанию TARS-CLI сам попытается это сделать, но в случае ошибки это придется сделать пользователю. * Обновление шаблона страницы и модуля head. Убраны лишние атрибуты, приведено к виду в [html5boilerplate](https://github.com/h5bp/html5-boilerplate) последней версии. * **Вместо префиксов %=staticPrefixForCss=% и %=staticPrefix=% можно использовать просто %=static=% или \_\_static\_\_ как в html, так и в css. Старые префиксы работают, но лучше использовать новый вариант.** * staticPrefixForCss был удален из tars-config, генерируется в tars/tars.js Представляет собой обычное поле-строку. * normalize обновлен до 3.0.3 * **[Добавлена возможность использовать кастомные хелперы для Handlebars и Jade.](html-processing.md)** * Добавлен хелпер icon для Jade и Handlebars, который генерирует шаблон для подключения svg-symbol в HTML. * Появилась возможность использовать [svg-символы](svg-processing.md#svg-symbols). Доступны 3 режима работы с symbols. Сборка для IE8 не производится, при выборе этого способо работы с SVG. В separate-js добавлен полифил для корректной загрузки символов из отдельного файла для IE и других браузеров, которые этого не поддерживают. * Поле useSVG удалено из конфига. Теперь SVG конфигурируется [отдельным объектом в tars-config](options.md#svg). Если поле есть (в случае использования старого конфига), то будет использоваться оно и генерироваться SVG-спрайт. * [В данных всегда генерируется массив с информацией о всех страницах проекта](html-processing.md#html). * Спрайты (svg, svg-symbols, png) версионируются при использовании флага `--release`. * port для Browsersync можно задать с помощью [переменной окружения](options.md#open). * Обновлен [конфиг autoprefixer по умолчанию](options.md#autoprefixerconfig). Удалена поддержка префиксов для ios 5.0. Доля этой ОС меньше 1% на данный момент. * Путь до папки со скриптами, картинками и стилями генерируется автоматом для страниц, в соответствии с их (страниц) вложенностью в директории. Теперь опцию %=static=% (\_\_static\_\_) не нужно править руками для каждой сборки, если у вас в pages есть иерархия каталогов. * При сборке проекта без ключей `--ie`, `--ie9`, `--ie8` вырезаются все соответствующие условные комментарии. В готовый билд больше не попадает лишних файлов. Например, при сборке без ключа `--ie` или `--ie8` файл html5shiv не переносится в билд * Удален hml5shiv-print. * Внтури data-файлов можно использовать JavaScript-объект, в случае, если IDE ругается на текущий синтаксис data-файла. * Появилась возможность [инициализировать проект без изменения файлов шаблонизатора или css-препроцессора](https://github.com/tars/tars-cli/blob/master/docs/ru/commands.md#tars-init). Это будет полезно владельцам форков. * [Появилась возможность автоматического обновления TARS в проекте с помощью TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/ru/commands.md#tars-update-project). * **Таск re-init теперь запрещен для использования. В дальнейшем эта команда не будет поддерживаться и будет удалена из проекта, так как есть вероятность сломать проект при ее использовании.** * Обновленна документация. ## Version 1.5.0 * Пофиксил установку в NPM3. В том случае, если у вас есть проект, который был разработан на TARS 1.4.1 и NPM2, а сейчас вы используете NPM3, необходимо заменить одну строку в tars/tars.js: ```javascript handlebars: tars.require('gulp-compile-handlebars/node_modules/handlebars'), // заменить на handlebars: tars.require('handlebars'), ``` * Используется Handlebars из отдельно установленного пакета, а не из gulp-handlebars. * Добавлена возможность использования css-файлов в папке etc. ## Version 1.4.1 * Добавлен понятный лог при ошибках в css. * Обновлена [документация по использованию Babel](js-processing.md). * Поправлен конфиг html-prettify. * Нотификации при ошибках появляются, даже если они отключены. * Обновлены версии зависимостей, пофикшены баги. ## Version 1.4.0 * Добавлена возможность использовать import в стилях. Css (less, scss, sass, styl) файлы с _ в начале файла не компилируются. Только их рекомендуется импортировать. [Подробности в документации](css-processing.md). * Добавлена поддержка .sass расширения для файлов стилей. * Обновлен tars-config. Поле [sourcemaps](options.md#sourcemaps) теперь имеет больше опций. Добавлен конфиг включения [Babel](options.md#usebabel). * Добавлена поддержка синтаксиса ES6(ES.Next) с помощью [Babel](options.md#usebabel). [Подробности в документации](js-processing.md). * Autoprefixer вставляется самым последним, сразу после всех используемых постпроцессоров. * Notifier получил единый интерфейс. При отключенных нотификациях теперь не будет вообще никаких уведомлений в системе, даже при ошибках. Ошибки будут отображаться только в консоли. При включенных все будет как обычно. Поменялся формат нотификаций в системе, теперь выводится иконка TARS. * Добавлен gulp-html-prettify. Теперь скомпилированный html будет отформатирован, если опция [minifyHtml](options.md#minifyhtml) установлена в false. * Стили для IE9 не собираются автоматически. Для того, чтобы получить сборку необходимо использовать флаг `--ie9` или `--ie`, чтобы собрать под IE8 и IE9. * Добавлены хелперы для Handlebars. Описана возможность добавления своих хелперов. Хелперы перенесены в репозиторий tars-handlebars и находятся рядом с тасками. ## Version 1.3.1 * Фикc конфига для PostCSS. Теперь не надо руками реквайрить постопроцессоры. Вы просто перечисляете постпроцессоры, которые хотите использовать в конфиге и все. Но не забудьте установить локально используемые постпроцессоры через NPM. ## Version 1.3.0 * Добавлены sourcemaps для JavaScript. Теперь можно увидеть в браузере не только файл из исходников, но даже путь до этого файла. * Добавлен [PostCSS](https://github.com/postcss/postcss) и [возможность добавлять любые другие постпроцессоры](options.md#postcss). Отдельно использовать PostCSS пока нельзя, только совместно с каким-либо препроцессором. * Убраны нотификации во время сборки. Теперь они будут появляться только тогда, когда они действительно нужны. * Добавлена поддержка расширения .hbs для Handlebars-шаблонов. * Добавлен padding между картинками в растровом спрайте. * Отрефакторены основные модули и страницы. * Теперь browsersync открывает бразер, установленный в системе по умолчанию, если [не указано иначе](options.md#browser). * Созадана новая сущность, tars, которая содержит в себе все методы и ссылки на зависимости, необходимые сборщику. * [Создан TARS-CLI](https://github.com/tars/tars-cli/blob/master/README_RU.md). * Поправлены различные баги. ## Version 1.2.7 * Поправлен баг в gulp-svg-spritesheet. ## Версия 1.2.6 * Поправлен баг нотификацией, когда она отключена. ## Версия 1.2.4 * Поправлен баг с инициализацией TARS. * Исправлена ошибка при собирании png-спрайта ## Версия 1.2.3 * Починил баг работы TARS c выкюченным нотификатором. ## Версия 1.2.2 * Внесен фикс в вотчер assets-файлов модуля. На данный момент поддиректории в папке assets в модуле не поддерживаются. ## Версия 1.2.1 * Обновлен code-style. Обновлен .jscsrc * Добавлено описание workflow для [контрибутеров](for-contributors.md). * Убрал модуль path из зависимостей. * Добавлены доки на английском языке. ## Версия 1.2.0 * Новая версия [Browsersync](https://www.browsersync.io/). * Опция [baseDir](options.md#basedir) для Browsersync перемещена в tars-config. * Вотчеры используют модуль [chokidar](https://github.com/paulmillr/chokidar) * Все вотчеры переехали в отдельные файлы в папку tars/watchers. * Сделана автозагрузка вотчеров и тасков в gulpfile. * Таск 'builder-start-screen' переехал в tars/tasks/services. * Добавлены новые хэлперы в handlebars (и [документация по ним](handlebars-helpers.md)). Все хелперы хранятся в отдельном файле tars/helpers/handlebars-helpers.js * Добавлена папка framework по пути markup/static/js Папка предназначена для js-файлов используемого фреймворка. * Обновлены зависимости. * Изменился синтаксис подключения модулей при использовании Handlebars. Старый синтаксис: ```handlebars {{> modules/head/head head.defaults}} ``` Новый: ```handlebars {{> head/head head.defaults}} ``` * Больше нет отдельного таска для компилирования стилей для ie9. Стили для ie9 компилируются в рамках таска компилирования стилей для всех современных браузеров. Отдельный файл создается. * Поменялся workflow подготовки svg-графики. Кодирование в base64 было заменено на отдельный svg-sprite. Использование в коде не изменилось. * mData/mData.js –> data/data.js ## Версия 1.1.1 * Исправлен баг в таске переноса js из separate-js. Было указано старое название папки. ## Версия 1.1.0 * Добавлен user-package.json для пользовательских зависимостей. Изменения в tars/helpers/install-additional-deps.js * Добавлено [руководство по обновлению TARS](update-guide.md) * Обновлен модуль [gulp-sass](https://www.npmjs.com/package/gulp-sass). * Генерация версии сборки перенесена в отдельный хелпер, что упрощает ее кастомизацию. Находится тут: tars/helpers/set-build-version.js ================================================ FILE: docs/ru/css-concat-processing.md ================================================

English description | Описание на русском

# CSS concat processing Склейка стилей происходит в следующем порядке: * Normalize * Стили для библиотек * Mixins, sprites * Fonts * Vars * GUI * Common stylies (common.scss) * Стили для плагинов (static/scss/plugins, включая все поддиректории) * Стили компонентов (.css поддерживается) * Стили из etc.{scss,css} Также есть возможность использовать CSS-файлы, не включая их в общий бандл. Для этого в папке static/scss есть папка separate-css, в которой вы можете положить все css-файлы, подключением которых вы будете управлять самостоятельно. Пример подключения такого файла в любом шаблоне: ```handlebars ``` **Префикс %=staticPrefix=% все еще работает, но крайне не желательно его использовать, так как в будущих версиях он будет удален! Используйте просто %=static=% или \_\_static\_\_!** ================================================ FILE: docs/ru/css-manual-processing.md ================================================

English description | Описание на русском

# CSS manual processing Данный подход будет полезен, если вам не хватало контроля над сборкой стилей при автоматической конкатенации. В данном режиме вы полностью управляете процессом (и порядком) сборки стилей в проекте. Ручное управление стилей досутпно с TARS версии 1.8.0 и выше. Основные точки входа, файлы стилей, в которые будут импортироваться стили вашего проекта, находятся в папке static/scss/entry. По умолчанию там уже находится одна точка входа — main.scss Вы можете добавить еще точек входа, если вам это потребуется. Именно эти файлы будут компилироваться препроцессором. Файлы вашего проекта необходимо подключать в точки входа с помощью конструкции @import. Подключение точки входа по умолчанию (main) уже описано в шаблонах (components/head/). В случае добавления новых точек входа, их требуется подключать в шаблонах вручную. Содержимое main.scss выглядит следующим образом: ```scss @import '../normalize.scss'; /* Libraries, which is used in current project. */ @import 'partials/_libraries.scss'; /* Libraries, which is used in current project. */ @import 'built-in-partials/_service.scss'; /* Plugins, which is used in current project. */ @import 'partials/_plugins.scss'; /* Components, which is used in current project. */ @import 'partials/_components.scss'; /* Additional style files. */ @import '../etc/etc.scss'; ``` В точку входа импортируется normalize.scss, затем партиал, в который вы можете импортировать библиотеки, затем встроенные партиалы (различные миксины для правильной работы с графикой в проекте и т.д.), партиал с плагинами, партиал с компонентами и другие стили. Партиал с компонентами означает, что именно в этот файл вы будете импортировать стили своих компонентов. При этом вам не обязательно указывать относительный путь до стилей компонентов от файла партиала. Достаточно сделать так: ```scss @import 'components/_template/_template.scss'; ``` Подключение стилей для плагинов и библиотек из node_modules и bower_components описано в [общей доке по работе со стилями](css-processing.md). Большая просьба: **не редактируйте файлы из директории built-in-partials, они могут быть перезаписаны в результате обновления проекта!**. Также в entry есть директория ie, в которой вы можете добавить точки входа для ie8 и ie9. Точки входа для ie9 должны иметь суффикс _ie9, а для ie8 — _ie8. Обратите внимание, для этих точек входа вам необходимо подключать стили компонентов, если они есть для этих браузеров. Нет необходимости дублировать содержимое _components и _components-ie9. В _components-ie9 должны быть только стили компонентов для ie9. ================================================ FILE: docs/ru/css-processing.md ================================================

English description | Описание на русском

# CSS В качестве CSS-препроцессора можно использовать: * [Scss](http://sass-lang.com) также поддерживается .sass; * [Less](http://www.lesscss.org); * [Stylus](http://learnboost.github.io/stylus). CSS-препроцессор выбирается в [tars-config.js](options.md#csspreprocessor). В целом, нет каких-либо неожиданностей при использовании CSS-препроцессора. Используем все возможности, которые предоставляет выбранный инструмент. Если вы привыкли к обычному CSS, вы можете использовать CSS-синтаксис в любом препроцессоре. В TARS поддерживается два подхода для работы со стилями: * [автоматическая склейка стилей сборщиком](css-concat-processing.md); * [Ручное управление подключаемыми стилями](css-manual-processing.md). Все, что описано ниже справедливо для обоих подходов. Все файлы с префиксом _ не будут компилироваться сборщиком. Эти файлы нужно использовать для импортов. На самом деле вы можете импортировать любые файлы, но если вы импортируете файл, который итак попадет в бандл, у вас будет две копии одного и того же файла. Поэтому файлы с префиксом _ не компилируются. Импортировать можно как файлы препроцессора, так и обычные CSS-файлы. Пример импорта на scss(sass): ```scss // файлы лежат в одной директории @import '_partial.scss'; // _partial.sass лежит в соседней директории partials @import '../partials/_partial.sass'; ``` Если требуется подключить файлы из node_modules или bower_components, можно не писать полный путь, а использовать сокращенный синтаксис, TARS сам достроит путь: ```scss @import 'bootstrap/dist/bootstrap.scss'; ``` В случае такого импорта TARS попытается найти bootstrap/dist/bootstrap.scss в node_modules и bower_components. Данная функциональность доступна с версии TARS 1.7.0 Если требуется подключить файлы из директории static (картинки), то необходимо пользоваться плейсхолдером %=static=% или \_\_static\_\_. Тогда подключение картинки в качестве background (в данном примере картинка будет взята из вашего компонента main) будет выглядеть следующим образом (в примере используется scss): ```scss .main { background: url('%=static=%assets/main/bg.png') repeat; } ``` **Префикс %=staticPrefixForCss=% все еще работает, но крайне не желательно его использовать, так как в будущих версиях он будет удален! Используйте просто %=static=% или \_\_static\_\_! Новый вариант префиксов работает в TARS, начиная с версии 1.6.0** Есть пара моментов по организации scss|sass|less|styl-файлов (далее считаем, что был выбран scss в качестве CSS-препроцессора): * Каждый компонент имеет свое CSS-представление. * Общие стили для проекта рекомендуется складывать в common.scss в static/scss * Подключение шрифтов в fonts.scss * Миксины в mixins.scss * Описание стилей UI-элементов в GUI.scss * Переменные в vars.scss * Стили библиотек в static/scss/libraries (может содержать подпапки и CSS-файлы) * Стили для плагинов в static/scss/plugins (может содержать подпапки и CSS-файлы) * Стили, которые не ясно, куда определить, помещаем в static/scss/etc/etc.{scss,css} * В основной папке с CSS (в данном случае это папка scss) нельзя создавать новые файлы (кроме тех случаев, когда вы сами правите таски, связанные с работой с css). Новые файлы можно создавать только в static/scss/plugins|libraries|etc|separate-css. Если вам необходимо подключить стили bower- или npm-пакета, то используйте import нужных стилей из пакета. Для браузеров IE8 и IE9 можно размещать отдельные фиксы в папке ie в папке компонента. Нужно создать ie8.{scss,sass,css} или ie9.{scss,sass,css}, в соответствии с тем, в какой браузер вносится фикс. ================================================ FILE: docs/ru/faq.md ================================================

English description | Описание на русском

# FAQ По всем вопросам можно обращаться в [gitter](https://gitter.im/tars/tars?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) или по почте [tars.builder@gmail.com](mailto:tars.builder@gmail.com). 1. **У меня webpack и NPM-scripts, я не понимаю, зачем нужен TARS с Gulp?** Для всего есть свой инструмент. Естественно, можно извернуться и для всех своих задач использовать только NPM-scripts. Но Gulp — это не только таск-менеджер (что уже делает его на одну ступень выше по удобству, чем NPM-скрипты), но и возможность легко переносить файлы в поток. С NPM-скриптами уже не так просто сделать правильную параллельную обработку задач. В любом случае потребуется еще некий index.js, в котором будет отдельно реализован последовательный flow выполнения тасков и параллельный. Также, не забываем, что и асинхронные задачи бывают. Насчет именно webpack: инструмент был создан для того, чтобы разрешать зависимости в JavaScript изначально. Сейчас его обвесили еще плагинами, но его главная задача так и осталась прежней. Отсюда следует, что Gulp + webpack = любовь, они не конкуренты друг другу. Можно почитать комментарии на эту тему [в документации к webpack + Gulp](http://webpack.github.io/docs/usage-with-gulp.html). 2. **Почему именно Gulp, а не Grunt?** Gulp это потоковый сборщик проектов на JavaScript. Он использует Streams и действительно является очень быстрым. Для примера у меня есть проект, где около тысячи stylus файлов, Grunt'у нужно примерно 2.5 секунды на сборку и 2 секунды на обработку autoprefixer'ом. Gulp все это делает за 0.5 секунды выигрывая у Grunt минимум в 4 раза. 3. **Как лучше построить процесс разработки с помощью TARS?** Единого ответа тут нет. Все зависит от специфики разработки. Рассмотрим несколько типов проектов. * Долгоиграющий и единственный. В этом случае все просто. Создавайте компоненты, страницы, храните все в какой-либо CVS — в общем, этот сценарий самый скучный. * Много проектов с повторяющейся функциональностью. В этом случае есть несколько путей работы с TARS: - создать библиотеку переиспользуемых блоков и включить ее сразу в собственный форк TARS. Таким образом, при ините нового проекта в нем сразу будут все нужные блоки; - использовать git или любую другую CVS. Пусть заиниченный TARS находится в git, а каждый новый проект — отдельная ветка; - хранить библиотеку повторяющихся блоков отдельно. * Много разных проектов. Также весьма простой сценарий, при котором каждый проект может быть отдельным репозиторием в git (или другой CVS). Указанные способы выше — не догма, а лишь пример, как получить больше пользы от TARS. 4. **У нас в команде есть свой сборщик на Gulp/Grunt, хотелось бы использовать наработки из него в TARS.** Можете перенести необходимые таски в user-tasks. Для использования grunt-тасков, если не хотите переписывать на Gulp, есть пакет [gulp-grunt](https://www.NPMjs.com/package/gulp-grunt), который запускает grunt-таск в Gulp. Но все же рекомендуем портировать grunt-таск в Gulp. Тем более, все плагины для Grunt доступны в Gulp. Если необходимо, чтобы проект инитился всегда с этими дополнительными тасками, то рекомендуем создать форк TARS, добавить в нем необходимые изменения, [инитить проект, с указанием ссылки на ваш форк](https://github.com/tars/tars-cli/blob/master/docs/ru/commands.md#tars-init). При этом, для упрощения обновления форка, все кастомные таски следует складывать в users-tasks, а зависимости для этих тасков указывать в user-package.json. Они будут ставиться с каждым заиниченым проектом. 5. **У меня OS X (Ubuntu, Linux Mint ...) В готовую сборку попадают не все файлы проекта.** Нужно увеличить [ulimit](options.md#ulimit) в tars-config.js 6. **Я ничего не понимаю в Gulp, могу ли я комфортно пользоваться данным сборщиком?** Знания работы с Gulp не обязательны. На данный момент сборщик покрывает большинство задач frontend'а. Все, что нужно знать — описано в документации. 7. **Мне кажется, что используется слишком сложная файловая структура. Могу ли я ее модифицировать так, как нужно мне?** Если вы умеете работать с Gulp, то после переименования/удаления/создания папок, необходимо править соответсвующие таски или [создавать user-tasks](tasks.md). Некоторые каталоги не обязательны и могут быть спокойно удалены. Также можно спокойно расширять файловую структуру для JavaScript с использованием [опции](options.md#jspathstoconcatbeforemodulesjs-%D0%B8-jspathstoconcataftermodulesjs) в конфиге сборщика. Для основной папки со статикой и папки с картинками можно задать имя в [опциях](options.md#fs) в конфиге сборщика. 8. **Вроде бы все поставилось, но ничего не работает. Что делать? У меня Windows (7, 8, 10)** Скорее всего не все зависимости поставились. Запустите команду `NPM i` еще раз. Если в результате выполнения данной команды есть ошибки, то большая просьба прислать их на почту ([tars.builder@gmail.com](mailto:tars.builder@gmail.com)) или в [gitter](https://gitter.im/tars/tars?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge). ================================================ FILE: docs/ru/file-structure.md ================================================

English description | Описание на русском

# Файловая структура **Вся файловая структура генерируется автоматически. Руками ничего создавать не нужно!** Сборщик имеет следующую файловую структуру: ``` ├── gulpfile.js # gulpfile сборщика ├── tars.json # Системный файл с информацией о текущей версии ├── tars-config.js # Конфигурационный файл ├── package.json # Основные зависимости ├── .babelrc # Конфиг для Babel ├── .eslintrc # Конфиг для eslint ├── user-package.json # Пользовательские зависимости └── tars/ # Таски и хелперы для gulp ├── helpers/ # Хелперы ├── tasks/ # Основные таски (разложены по папкам в соответствии с типом таска) ├── user-tasks/ # Пользовательские таски ├── watchers/ # Основные вотчеры (разложены по папкам в соответствии с типом отслеживаемых файлов) ├── user-watchers/ # Пользовательские вотчеры └── tars.js # Основной файл сборщика ├── markup/ # Основная папка с проектом ├── components/ # Компоненты ├── pages/ # Шаблоны страниц └── static/ # Различная статика (css, js и т.п.) └── docs/ # Документация ``` ## Структура отдельного компонента Компонент — самостоятельная единица на странице. Пример компонента — «header» или «footer». Каждая страница состоит из компонентов. Компоненты могут подключать друг друга и быть вложены друг в друга. ``` exampleComponent/ # Пример компонента ├── assets/ # Файлы, относящиейся только к данному компоненту (файлы любого типа) Поддиректории не поддерживаются. ├── ie/ # Cтили для IE8 и IE9 (ie9.scss|sass|less|styl и ie8.scss|sass|less|styl) ├── data/ # Папка для хранения данных для компонента └── data.js # Данные для компонента в виде js-объекта (формат объекта есть в компонентк-примере _template) ├── exampleComponent.html # Html-представление компонента (также может иметь расширение jade или hbs, в зависимости от выборанного шаблонизатора) ├── exampleComponent.scss|sass|less|styl # Css-представление компонента (scss|sass|less|styl, в зависимости от выбранного css-препроцессора) ├── exampleComponent.js # Js-представление компонента └── anotherComponentFolder ``` Любой компонент может быть вложен (как структурно, так и в коде) в любой другой. Изображения из директории assets в результате сборки будут перемещены в static/img/assets/имя_компонента или static/img/assets/имя_компонента/имя_вложенного_компонента, если у компонент вложен в другой компонент. К картинкам относятся: svg, png, jpg, jpeg, jpe, gif, tiff и bmp. Все остальные файлы будут помещены в папку components-assets (имя папки зависит от опции fs.componentsFolderName). Основная идея в том, чтобы сделать компонент как можно более изолированной структурой. Здесь можно использовать [BEM](https://ru.bem.info), [веб-компоненты](http://webcomponents.org) (и их [реализация от Google](https://www.polymer-project.org)), что-то еще. Можно все делать и по старинке, внутри одного компонента вся верстка, но это крайне не рекомендуется. Если говорить терминами BEM, то каждый компонент — это блок. Есть отличная лекция о том, как лучше организовать свой код, [ссылка](https://www.youtube.com/watch?v=pyAYbbDJjPo). В `pages` находятся шаблоны страниц, в которые в итоге будут включены компоненты. Страницы являются лэйаутом и должны содержать в себе как можно меньше кода, чтобы структура была как можно более прозрачная. Чтобы создать новую страницу, просто скопируйте существующую (или _template) и переименуйте или [используйте tars add-page](https://github.com/tars/tars-cli/blob/master/docs/ru/commands.md#tars-add-page-pagename). Также вы можете добавить компонент с помощью TARS-CLI — [tars add-component](https://github.com/tars/tars-cli/blob/master/docs/ru/commands.md#tars-add-module-modulename). ## Структура папки для статики Будем считать, что css-препроцессором был выбран Scss. ``` static/ # Папка для статики. Название для папки настраивается в tars-config.js ├── fonts/ # Шрифты (может содержать поддиректории) ├── img/ # Картинки. Название для папки настраивается в tars-config.js ├── content/ # Контентные картинки (может содержать поддиректории) ├── plugins/ # Картинки для плагинов (может содержать поддиректории) ├── general/ # Общие картинки для проекта (может содержать поддиректории) ├── sprite/ # Растровые картинки, которые должны быть включены в спрайт (png) ├── 96dpi/ # Картинки для экранов с dpi 96 ... └── 384dpi/ # Картинки для экранов с dpi 384 (более подробно в разделе работы с изображениями) └── svg/ # SVG-картинки ├── js/ # js ├── framework/ # js-фреймворки (например, backbone) ├── libraries/ # js-библиотеки (например, jquery) ├── plugins/ # js-плагины └── separate-js/ # js-файлы, которые не должны попасть в итоговый склеенный js-файл. ├── misc/ # Общие файлы, которые будут перемещены в корень собранного проекта — фавиконка, robots.txt и т.д. (может содержать поддиректории) └── scss ├── entry/ # Стили, для точек входа при ручном управлении компиляции стилей. Подробнее [тут](css-manual-processing.md). ├── etc/ # Стили, которые будут подключаться в самом конце (может содержать поддиректории) ├── libraries/ # Стили библиотек (может содержать поддиректории) ├── plugins/ # Стили для плагинов (может содержать поддиректории) ├── separate-css/ # Стили, которые не должны попасть в итоговый склеенный css-файл. ├── sprite-generator-templates/ # Шаблоны, по которым генерируются спрайты ├── sprites-scss/ # Миксины для спрайтов ├── common.scss # Общие стили для всего проекта ├── fonts.scss # Стили для подключенный шрифтов ├── GUI.scss # Стили для GUI-элементов типа кнопок, полей ввода и т.д. ├── mixins.scss # Набор миксинов ├── normalize.scss # Сброс стилей └── vars.scss # Переменные проекта ``` ## Структура готовой сборки После сборки проекта в корне появятся две папки: dev и builds. Ниже дано описание dev-версии сборки (С включенным режимом --ie8), так как готовый билд не сильно отличается от dev. ``` dev/ └── static/ # Статика для проекта (имеет имя, заданное в tars-config) └── css/ # Готовые файлы стилей для всех основных браузеров, IE9 и IE8, если включена их поддержка и стили, которые не вошли в общую сборку. └── components-assets/ # Файлы для компонентов. └── exampleComponent/ └── img/ # Картинки для проекта └── assets/ # Файлы для компонентов. Содержит в себе директории с именами тех компонентов, которые имеют доп. файлы (только картинки) └── exampleComponent/ └── content/ # Картинки для контента └── plugins/ # Картинки для плагинов └── svg-sprite/ # SVG-спрайт └── png-sprite/ # PNG-спрайты для разных dpi └── rastered-svg-images/ # Отрастированные svg-картинки для IE8 └── minified-svg/ # Минифицированные svg └── js/ # Итоговый main.js файл и js-файлы, которые не должны попасть в общую сборку. └── separate-js/ └── temp/ # Папка для данных для компонентов ├── Готовые страницы и файлы из папки misc ``` build-версия проекта не содержит папки temp, включает минимизированные css- и js-файлы. Содержит оптимизированные картинки и архив с собранным проектом (опционально). Если включена опция useBuildVersioning, то каждый билд будет лежать в отдельной папке по пути, который указан в опции [buildPath](options.md#buildpath), под названием build_ver%дата сборки%. Если useBuildVersioning отключен, то готовый проект находится по пути, который указан в опции [buildPath](options.md#buildpath), в папке build. При подключении картинок необходимо использовать именно тот путь, по которому они лежат в собранном проекте. Сразу после инициализации или переинициализации в корне могут появиться папки .tmpPreproc и .tmpTemplater, в которых находятся скачанные шаблонизатор и css-препроцессор. При первой же сборке эти папки будут удалены. Так что просто не обращайте на них внимание. Эти папки влючены в .gitignore, так что они точно не попадут в ваш репозиторий. Данную файловую структуру можно менять, с правкой соответствующих тасков и вотчеров. Для некоторых папок нет необходимости лезть в таски и вотчеры. Например, можно создать папки для хранения js, [который должен быть выполнен до компонентов и после](options.md#jspathstoconcatbeforemodulesjs-и-jspathstoconcataftermodulesjs). Это будет полезно при использовании различных js-фреймворков. Также не обязательно пользоваться всеми папками для изображений или js. Если что-то не нужно, это можно удалить. ================================================ FILE: docs/ru/fonts-and-misc.md ================================================

English description | Описание на русском

# Работы со шрифтами и misc-файлами Все шрифты размещаются в папке fonts в папке со статикой для проекта. В папке misc можно хранить любые дополнительные файлы проекта, например фавиконку и т.п. Все файлы отсюда буду скопированы в корень скомпилированного проекта. Поддерживается вложенность директорий. При копировании файлов иерархия папок будет сохранена. ================================================ FILE: docs/ru/for-contributors.md ================================================ # Руководство для контрибьютеров ## Code style За основу берем [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript). На русском [uprock/javascript](https://github.com/uprock/javascript). Есть небольшие отличия в code style Airbnb от того, как нужно писать JavaScript в TARS: 1. **Пробелы и табуляция** Для отступов и табуляции используем 4 пробела, а не 2: ```javascript function () { ∙∙∙∙const name; } ``` 2. **Длина строки (line length).** Требования длины строки в 80 символов следует считать опциональным. Т.е. строки не должны быть слишком длинными, и должны помещаться в окно редактора даже на небольшом мониторе. 3. **Комментарии.** Ко всем неочевидным с первого взгляда кускам кода пишем комментарии. Обязательно !осмысленные! и на английском языке. Все комментарии будут модерироваться, поэтому стараемся писать на хорошем английском. 4. **Строгое равенство/не равенство (=== / !==)** Исходим из здравого смысла и пользуемся только там, где это действительно необходимо. Например в случаях с `null` или `undefined`. 5. Используем стрелочные функции по-максимуму. 6. Используем const для всего, что не будем менять. let — для переменных внутри блока (циклы), var — функциональная видимость переменной. Чтобы проверить, все ли учтено в вашем коде, прогоните его через eslint с настройками, которые лежат в корне TARS. ## Правила работы с ветками, issue и т.д. Вы можете создать Pull request как в мастер, так и в отдельную ветку. ### Реквест в мастер В данном случае необходимо, чтобы код соответсвовал code-style, в нем не было ошибок и он не менял функциональность TARS — не добавлял и не убирал. Если предполагается изменение функциональности, то реквест необходимо делать в ветку с текущей разрабатываемой версией. Необходимо добавить описание к реквесту, желательно на английском языке. Если есть проблемы с англйиским, то пишем описание на русском. ### Реквест в ветку или реквест ветки Ветка должна иметь вменяемое имя, в котором кратко будет описано, о чем эта ветка. Запрещается название веток на русском языке. Если ваша правка относится к какой-либо версии, то название ветки должно начинаться так: version-\*.\*.\*-add-something. Звездочки — конкретная версия, к которой относится реквест. Например, version-1.3.0-add-sourcemaps. ### Работа с issue Если вы хотите выполнить какой-либо issue, важно получить одобрение на его выполнение от @artem-malko. Чтобы оставить заявку, достаточно написать в комментарии к задаче: `I'll make it`. После этого нужно получить от меня большой палец (смайл в виде большого пальца поднятого вверх) и на задаче должен появиться лэйбл `in progress`. После этого можно брать задачу в работу. Задачу необходимо выполнять в отдельной ветке, которая образована от ветки текущей разрабатываемой версии, например от version-1.3.0. О том, как создавать реквест в ветку рассказано выше. Дополнительные контрибуторы не допускаются, если на задаче есть лейбл `in progress`. Если ваша задача перекликается по функциональности с другой, важно договориться об этом с исполнителем конфликтующей задачи, как вы будете в дальнейшем работать над конфликтующими участками кода. Брать в работу можно только ту задачу, у которой есть хотя бы 1 лэйбл (кроме лейбла backlog) и она имеет какую-либо версию. Задачи без версии в работу не беруться, однако тут можно обсудить отдельно, возможно, задача может попасть в какой-либо ближайший релиз, если вы готовы ее выполнить. ### Создание pull-реквестов После того, как вы закончили работу над какой-либо задачей, необходимо создать pull request в мастер или в ветку. В реквесте необходимо кратко описать, что было сделано, на что стоит обратить внимение. Также нужно указать ссылку на задачу, которую реквест решает. Все реквесты должны пройти аппрув от @artem-malko и тесты в travis и appveyor. Аппрув — 1 большой палец от @artem-malko. Если задачу сделал @artem-malko, то необходим палец любого другого разработчика. Внимание! Сливать свой реквест можно только после аппрува @artem-malko. После того, как реквест слит, необходимо удалить ветку, в которой велась работа. ================================================ FILE: docs/ru/handlebars-helpers.md ================================================

English description | Описание на русском

# Handlebars-helpers В TARS есть несколько полезных встроенных хелперов. Также есть возможность добавлять свои хелперы в файл /tars/user-tasks/html/helpers/handlebars-helpers. Вам не нужно регистрировать новый хелпер, необходимо его только объявить как поле объекта «handlebarsHelpers», как функцию. Все кастомные хелперы будут автоматически доступны в шаблонах. Кроме того, все эти хелперы будут автоматически перенесены при обновлении проекта с помощью TARS-CLI. Поговорим о встроенных хелперах. ## repeat Используется для создания простого цикла от 0 до n ([цикл для обхода массива данных есть в handlebars по-умолчанию](http://handlebarsjs.com/builtin_helpers.html)). Синтаксис: ```handlebars {{#repeat n}} Do something {{/repeat}} ``` n — количество повторений. Number, целое. ## is Используется для расширения стандартного if. Встроенный if умеет проверять только существует значение или нет. #is позволяет использовать стандартное поведение if. Операция сравнения передается в виде строки вторым аргументом. 1 и 3 передаются значения для сравнения. Доступны следующие операции (все операции выполняются в JavaScript, соответственно и результат сравнения получается таким же, как если бы это был if внутри JavaScript): * `==` нестрогое равно; * `===` строгое равно; * `>` строго больше; * `>=` больше или равно; * `<` строго меньше; * `<=` меньше или равно; * `!=` нестрогое неравенство; * `!==` строгое неравенство. test — переменная, переданная в шаблон ```js testComponent: { test: 10 } ``` Синтаксис: ```handlebars {{#is test '>' 9}} true {{else}} false {{/is}} ``` ## strip Вырезает все пробелы из переданного контента. Синтаксис: ```handlebars {{#strip}} {{/strip}} ``` Результат: ```html ``` ## toLowerCase Перевод переданной строки в нижний регистр. Синтаксис: ```handlebars {{toLowerCase 'string'}} ``` ## toUpperCase Перевод переданной строки в верхний регистр. Синтаксис: ```handlebars {{toUpperCase 'string'}} ``` ## capitalizeFirst Перевод первого символа переданной строки в верхний регистр. Синтаксис: ```handlebars {{capitalizeFirst 'string'}} ``` ## formatDate, now, i18n Дополнительные хелперы. Документация по ним досутпна в репозитории проекта https://github.com/assemble/handlebars-helpers ================================================ FILE: docs/ru/html-processing.md ================================================

English description | Описание на русском

# HTML В качестве шаблонизатора для HTML можно использовать [Jade](http://jade-lang.com), [Pug](https://pugjs.org/api/getting-started.html) или [Handlebars](http://handlebarsjs.com). Шаблонизатор выбирается в [tars-config.js](options.md#templater) или во время [инициализации TARS с помощью TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/ru/commands.md#tars-init). Можно использовать любые средства данных шаблонизаторов. Если вы привыкли к ламповому HTML, то смело выбирайте Handlebars и просто пишите HTML как раньше. Если не требуется компиляция определенной страницы, то можно просто добавить '_' в начало названия страницы, и она не будет скомпилирована. Если необходимо подключить файлы из директории static (картинки, js-файлы), то необходимо пользоваться плейсхолдером [%=static=% или \_\_static\_\_](options.md#staticprefix). Тогда подключение картинки в контенте будет выглядеть следующим образом (в примере используется Handlebars): ```html ``` Для подключения картинки в CSS необходимо использовать тот же плейсхолдер – %=static=% или \_\_static\_\_. Данный плейсхолдер в CSS подставит значение из конфига [staticprefixforcss](options.md#staticprefixforcss). **Префиксы %=staticPrefixForCss=% и %=staticPrefix=% все еще работают, но крайне не желательно его использовать, так как в будущих версиях он будет удален! Используйте просто %=static=% или \_\_static\_\_! Новый вариант префиксов работает в TARS начиная с версии 1.6.0** Очень важной фичей является использование различных данных в одном шаблоне. Например, у нас есть компонент head, в котором находится все, что стоит поместить в тег head (различные meta, тайтлы и т.д.) Предположим, что на каждой странице должен быть свой title. Создавать копии одного и того же компонента, которые отличаются только одной строчкой — не целесообразно. Было бы логично отделить данные от представления. Поэтому в папке с компонентом есть папка `data`, в которой находится js-файл с данными данного компонента. Пример данных можно найти в компоненте _template: ```javascript componentName: { dataType: { property: value } } ``` Если у вас IDE ругается на синтаксис, то можно использовать обычный JavaScript-объект: ```javascript data = { componentName: { dataType: { property: value } } }; ``` Оба синтаксиса поддерживаются TARS по умолчанию. В файле data.js поддерживаются комментарии только внутри объекта с данными. С версии TARS 1.8.0 появилась возможность использовать вложенные компоненты. Может получиться такая ситуация, что вложенные компоненты в двух разных компонентах могут иметь одно название и одинаковый ключ в данных. Чтобы такого не происходило TARS генерирует уникальный ключ для вложенных компонентов следующим образом: ```javascript 'parentComponentName_anotherParentComponent_currentComponentName' = { dataType: { property: value } }; ``` При этом в самом вложеном компоненте вы пишете также, как и обычно: ```javascript const data = { 'currentComponentName': { dataType: { property: value } } }; ``` Все преобразования ключа происходят автоматически. По умолчанию в данных будут находится данные из компонента _template и список всех страниц проекта в виде: ```javascript __pages: [ { name: 'pageName', href: 'pageHref' } ] ``` Этот массив можно использовать для генерации списка ссылок всех страниц проекта. Также, в шаблон можно передать любые данные с помощью переменной окружения TARS_ENV. Например так можно передать простую строку: ```bash TARS_ENV="Hello World" tars dev --silent ``` Затем в шаблоне (handlebars): ```handlebars {{TARS_ENV}} ``` Также можно передавать объекты: ```bash TARS_ENV="{\"name\": \"Paul\"}" tars dev --silent ``` Затем в шаблоне (handlebars): ```handlebars {{TARS_ENV.name}} ``` **Обратите внимание, при передаче объекта в переменную окружения необходимо указывать двойные кавычки, а также экранировать их!** Подключение компонентов с различными данными выглядит по-разному в Jade/Pug и Handlebars. ##Работа с компонентами и данными в Handlebars Подключение компонента на странице: ```handlebars {{> componentFolderName/componentName}} ``` Подключение компонента с передачей данных в шаблон: ```handlebars {{> componentFolderName/componentName componentName.dataType}} ``` Пример подключения компонента head с данными типа defaults: ```handlebars {{> head/head head.defaults}} ``` Внутри самого компонента данные выводятся средствами Handlebars: ```handlebars {{title}} ``` Если вы не передали данные в компонент, то компонент получает доступ в глобальный контекст. Иными словами, если мы подключим компонент head без передачи данных, то в самом шаблоне мы можем получить доступ к полю title следующим образом: ```javascript // head/data/data.js head: { defaults: { title: 'Default title' } } ``` index.html ```handlebars {{> head/head}} ``` head.html ```handlebars {{head.defaults.title}} ``` Если же вы передали контекст с подключением компонента, то доступ к данным других компонентов вы уже не имеете внутри подключенного. Чтобы подключать компоненты внутри других компонентов со своими данными необходимо в компонент-родитель передавать глобальный контекст (не передавать никаких данных при подключении). Тогда вы сможете передать в любой дочерный компонент необходимые данные. Либо можно воспользоваться следующим способом: index.html ```handlebars {{> component1/component1 component1.main}} ``` component1.html ```handlebars

{{title}}

{{> component2/component2 component2.main}} ``` ```javascript // component1/data/data.js component1: { main: { title: 'Title of component1', component2: function (fullData) { return fullData.component2; } } } ``` component2.html ```handlebars

{{title}}

``` ```javascript // component2/data/data.js component2: { main: { title: 'Title of component2' } } ``` Таким образом, вы можете получить доступ к данным любого компонента из данных любого компонента простой конструкцией: ```javascript // component/data/data.js component: { main: { title: 'Title of component', innerComponentData: function (fullData) { // fullData — объект, который содержит все данные проекта return fullData.componentName.componentType; } } } ``` А если использовать стрелочные функции ES6, то все становится еще проще: ```javascript // component/data/data.js component: { main: { title: 'Title of component', innerComponentData: fullData => fullData.componentName.componentType } } } ``` Не забудьте, ключ доступа к данным вложенных компонентов будет сгенерирвоан автоматически на основе вложенности в другие компоненты. Handlebars известен, как очень простой шаблонизатор. Но использовать его в статической верстке в таком виде не очень удобно. Поэтому были добавлены различные хелперы, расширяющие возможности Handlebars.
Описание хелперов можно прочесть [здесь](handlebars-helpers.md). ## Работа с компонентами и данными в Jade/Pug При использовании Jade/Pug, каждый компонент — миксин, который подключается в файл страницы. Миксины могут принимать данные, этим и воспользуемся. Подключение компонента на странице: ```jade include ../components/componentFolderName/componentName // В начале шаблона страницы (пример — index.jade|pug) +componentName() // Подключение компонента ``` Подключение компонента с передачей данных в шаблон: ```jade include ../components/componentFolderName/componentName // В начале шаблона страницы (пример — index.jade|pug) +componentName(componentName.dataType) // Подключение компонента ``` Пример подключения компонента head с дефолтными данными: ```jade include ../components/head/head +head(head.defaults) ``` В случае использования Pug, вам необходимо указать расширение для подключаемого компонента: ```jade include ../components/head/head.pug +head(head.defaults) ``` Внутри самого компонента данные выводятся средствами Jade/Pug (например, компонент head): ```jade mixin head(data) #{data.title} ``` Можно использовать любые средства, доступные в Jade/Pug. Вы можете подключать компоненты с любой сложностью, с любыми данными. Функции в data.js также доступны, как и в примерах для Handlebars. В TARS есть один встроенный хелпер для Jade/Pug — хелпер `Icon`, который вставляет шаблон для подключения svg-symbol в HTML. Также есть возможность добавлять свои хелперы в файл /tars/user-tasks/html/helpers/jade|pug-helpers. Там же есть пример объявления хелпера. Все хелперы доступны в шаблонах следующим образом: Для Jade: ```jade = jadeHelpers.helperName(params) != jadeHelpers.helperName(params) ``` Для Pug: ```jade = pugHelpers.helperName(params) != pugHelpers.helperName(params) ``` ================================================ FILE: docs/ru/images-processing.md ================================================

English description | Описание на русском

# Images Всю работу с изображениями в TARS можно разбить на две части: «Спрайты» и «Отдельные изображения». ## Спрайты TARS поддерживает работу с двумя форматами изображений для спрайта: PNG и SVG. **TARS поддерживает несколько способов работы с SVG-графикой. Более подробно можно прочитать в [документации по работе с SVG](./svg-processing.md)** Общий подход отлично описан в [презентации](http://www.slideshare.net/codefest/codefest-2014-2) веб-разработчика [Тимофея Чаптыкова](https://github.com/Chaptykov). Кратко подход описан ниже. Преимущество данного подхода раскрыто в презентации и не будет объяснено ниже. Здесь не будут описаны преимущества склейки интерфейсных (и других мелких или частоповторяющихся изображений) в единый спрайт. Если вы не знакомы с понятием спрайт — подробности [по ссылке](https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D1%80%D0%B0%D0%B9%D1%82_(%D0%BA%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D0%BA%D0%B0)). Вы можете пропустить теорию и сразу [перейти к описанию работы со спрайтами](images-processing.md#%D0%9F%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D0%BF%D1%80%D0%B0%D0%B9%D1%82%D0%BE%D0%B2). Сегодня существует много экранов с высокой плотностью пикселей. Разберёмся, что это значит. В качестве примера рассмотрим смартфоны IPhone 3GS и IPhone 4. У 3GS разрешение экрана 320x480, а у 4-ки — 640x960. Как мы видим, разрешение увеличилось ровно в два раза при той же диагонали, а значит пиксель стал меньше. Чтобы нивелировать эту разницу между размерами пикселей (а ведь именно пикселями мы управляем в CSS) появился параметр device-pixel-ratio (или dppx), который показывает, сколько реальных экранных пикселей содержится в неком логическом пикселе, которым мы оперируем в CSS. Например, для дисплея IPhone 4 этот параметр равен 2. Более подробно можно прочесть [здесь](http://stackoverflow.com/questions/21971331/what-is-dots-per-css-inch-and-dots-per-physical-inch) и [здесь](http://www.w3.org/TR/css3-values/#absolute-lengths). Предположим у нас есть спрайт PNG-изображений. Такие картинки имеют фиксированные размеры. Если мы будем размазывать такую картинку на количество пикселей в 3 раза большее, чем размеры картинки, то изображение будет размыто. Чтобы избавиться от этой проблемы, можно использовать изображение в 3 раза большего размера для подобного экрана, при этом размер картинки в CSS задавать исходя из размера оригинального изображения (свойство background-size). На данный момент существуют экраны с dppx от 1 до 4 (скоро будут и выше). Готовить спрайты для 4 размеров экранов — это очень много работы. Выручает SVG. Векторный, не зависит от dppx экрана, отлично рендерится в современных (и не только) браузерах. Можно сделать только 1 размер и это изображение будет выглядеть одинаково на всех экранах. К сожалению SVG имеет несколько недостатков: * SVG плохо отображает радиальные и другие сложные градиенты (линейные отображаются отлично). * Плохо отображаются сложные тени. * Не отображается в IE8. Итого имеем два подхода: SVG для всего, чего можем. Для остального готовим PNG-изображения для тех экранов, которые вы собираетесь поддерживать. Для IE8 будем просто растрировать SVG-изображения. **TARS поддерживает несколько способов работы с SVG-графикой. Более подробно можно прочитать в [документации по работе с SVG](svg-processing.md)** ## Подключение растровых спрайтов Изображения, которые не могут быть отрисованы в SVG складываются в 'static/img/sprite/96dpi|192dpi|288dpi|384dpi'. В папку 96dpi кладутся изображения для экранов с dppx = 1, в папку 192dpi кладутся изображения в два раза больше оригинала, с названиями оригиналов. Данные изображения будут подключаться на экранах с dppx = 2. Далее по аналогии. Используемые экраны настраивается [в конфиге проекта](options.md#useimagesfordisplaywithdpi). Подключение иконки из растрового спрайта в CSS-коде производится с помощью миксина (пример на SCSS, названия миксинов и входные параметры для других CSS-препроцессоров такие же): ```scss @include bg($png-image-name); // Подключение спрайта с png-картинками ``` Обратите внимание, в миксин передается **переменная** с именем исходной картинки (без расширения). Миксин `bg` включит в CSS background, размер картинки, backgroud-size и задаст позиционирование внутри png-спрайта. Больше ничего добавлять не нужно, миксин сам задаст медиа-выражения для экранов с различной плотностью пикселей. ## Отдельные изображения Работа с отдельными изображениями очень проста. Отдельные изображения разделены на несколько категорий. В зависимости от категории картинки кладутся в разные места. Сборщик поддерживает изображения любого типа, но только SVG, PNG, JPG будут подвергаться минификации. !Все описанное ниже является лишь рекомендацией, вы можете организовать хранение картинок так, как вам удобно! ### Картинки компонента Находятся в папке assets внутри компонента. Для подключения используется следующий шаблон (для подключения картинки в HTML, необходимо использовать плейсхолдер [%=static=% или \_\_static\_\_](options.md#staticprefixforcss)): ```css .componentName { background: url('%=static=%assets/componentName/sample-image-name.png') no-repeat; } ``` В HTML подключение выглядит чуть иначе, но используется тот же плейсхолдер [%=static=% или \_\_static\_\_](options.md#staticprefix): ```handlebars
``` **Префикс %=staticPrefixForCss=% все еще работает, но крайне не желательно его использовать, так как в будущих версиях он будет удален! Используйте просто %=static=% или \_\_static\_\_! Новый вариант префиксов работает в TARS начиная с версии 1.6.0** В картинки компонента стоит складывать только те картинки, которые больше нигде не встречаются. Вложенность директорий поддерживается. ### Картинки для контента Находятся по пути (указан путь по умолчанию): 'static/img/content/'. В данную папку стоит класть картинки которые встречаются в контентных областях на сайте, например, на странице новости. Вложенность директорий поддерживается. Подключение картинки внутри HTML: ```handlebars
``` **Префикс %=staticPrefix=% все еще работает, но крайне не желательно его использовать, так как в будущих версиях он будет удален! Используйте просто %=static=% или \_\_static\_\_!** ### Картинки для плагинов Находятся по пути (указан путь по умолчанию): 'static/img/plugins/'. В данную папку стоит класть картинки которые используются в различных плагинах. Вложенность директорий поддерживается. ### Общие картинки Находятся по пути (указан путь по умолчанию): 'static/img/general/'. В данную папку стоит класть картинки которые используются по всему проекту, например общий фон сайта. Вложенность директорий поддерживается. ================================================ FILE: docs/ru/js-concat-processing.md ================================================

English description | Описание на русском

# Работа с JS с помощью простой склейки Данный workflow стоит использовать, если у вас простое приложение и нет надобности разрешать зависимости между файлами. При выборе данного подхода все JavaScript-файлы склеиваются в один общий файл в определенном порядке. Порядок и правила склейки описаны ниже. По умолчанию JavaScript находится в 2-ух местах: * В папке со статикой, в подпапке с именем js * В каждом отдельном компоненте. Можно добавить свои папки для js, используя соответствующую [опцию](options.md#jspathstoconcatbeforemodulesjs-%D0%B8-jspathstoconcataftermodulesjs) в конфиге сборщика. Весь JavaScript-код собирается в один отдельный файл, кроме JavaScript-файлов, которые находятся в директории separate-js. Эти файлы просто переносятся как есть в готовую сборку. Примером такого файла является html5shiv.js Файлы собираются в следующем порядке: * static/js/framework (включая подпапки) * static/js/libraries (включая подпапки) * static/js/plugins (включая подпапки) * все файлы, пути к которым находятся в опции jsPathsToConcatBeforeModulesJs * JavaScript-файлы компонентов * все файлы, пути к которым находятся в опции jsPathsToConcatAfterModulesJs **Файлы с _ в начале файла не будут попадать в общую сборку и не буду проверены линтером.** Проверкой файлов из jsPathsToConcatBeforeModulesJs и jsPathsToConcatAfterModulesJs можно управлять отдельно, опциями lintJsCodeBeforeModules и lintJsCodeAfterModules. ================================================ FILE: docs/ru/js-processing.md ================================================

English description | Описание на русском

# Работа с JS В TARS поддерживается два подхода в работе с JavaScript-кодом: * [склеивание всех JavaScript-файлов в один в определенном порядке](js-concat-processing.md); * [использование webpack, для разрешения зависимостей между файлами (доступно с версии 1.7.0)](js-webpack-processing.md). В обоих подходах поддерживается проверка кода с помощью eslint. Конфигурация eslint находится в корне проекта: .eslintrc и .eslintignore. Управлять проверкой кода можно с помощью опции [js.lint в конфиге проекта](options.md#lint). Также в обоих подходах есть возможность обработки JavaScript-кода с помощью [Babel](https://babeljs.io/). Для подключения Babel нужно использовать опцию [useBabel](options.md#usebabel) (по умолчанию выключено). Если вам необходимо исключить какие-либо файлы из обработки Babel, то вы можете добавить в начало названия этих файлов "babel_ignore_" или добавить их в секцию ignore в .babelrc в корне проекта. Все JavaScript-файлы из папок static/framework, static/libraries, static/plugins и static/separate-js находятся в ignore в .babelrc по умолчанию. С остальными опциями конфига Babel можно ознакомится на [официальном сайте](https://babeljs.io/docs/usage/options/). Вам не нужно использовать опции: 'filename', и все оцпии, связанные с sourcemaps. Эти опции уже заданы в самом сборщике. Sourcemaps вы можете управлять через опцию в [конфиге сборщика](options.md#sourcemaps). ================================================ FILE: docs/ru/js-webpack-processing.md ================================================

English description | Описание на русском

# Работа с JS через webpack **Есть большая просьба: все вопросы по настройке/работе с webpack адресовать в Google, Stack Overflow и т.д.** Для ознакомления с webpack рекомендую изучить [скринкаст Ильи Кантора](https://www.youtube.com/playlist?list=PLDyvV36pndZHfBThhg4Z0822EEG9VGenn) и [документацию по webpack](http://webpack.github.io/docs/). Скринкаст раскрывает множество особенностей при работе с webpack и его грамотной настройке. В TARS webpack уже настроен для того, чтобы с ним было достаточно комфортно работать. Но вы можете (и скорее всего вам придется это делать) изменять webpack-конфиг (файл webpack.config.js в корне проекта), чтобы webpack выполнял именно то, что вам нужно. По умолчанию используется только одна точка входа: markup/static/js/main.js. Вы можете использовать другой файл и сколь угодоно большое количество точек входа. **Необходимо использовать функцию prepareEntryPoints, в которую будет передаваться объект с информацией о точках входа. Это необходимо для корректной работы Hot Module Replacement!** По умолчанию webpack умеет разрешать зависмости, объявленные через require (import/export, если включена обработка кода через babel). При этом, в любой точке приложения вы можете подключить файл компонента с помощью алиаса «components». Предположим, что мы находимся в markup/static/js/main.js и хотим подключить в нем скрипт из компонента «example». Вместо указания относительного пути от main.js до example.js можно написать так: ```js import foo from 'components/example/example'; // useBabel: true // или const foo = require('components/example/example'); // Доступен и прошлый вариант const foo = require('modules/example/example'); ``` Также есть алиас для папки static, который позволит подключить файл из папки static в любой точке приложения: ```js import $ from 'static/js/jquery/jquery'; // useBabel: true // или const $ = require('static/js/jquery/jquery'); ``` Для подключения библиотек из node_modules достаточно указать имя пакета: ```js import $ from 'jquery'; // useBabel: true // или const $ = require('jquery'); ``` В webpack уже настроены sourcemaps, которыми вы можете [управлять из конфига проекта](options.md#sourcemaps). Sourcemaps сторонних плагинов и библиотек будут добавлены к обещму sourcemap (реализовано с помощью source-map-loader). Сжатие производится с помощью плагина uglifyJS. По умолчанию у вас есть возможность использовать переменную окружения NODE_ENV в коде. Подробнее можно узнать в [этом ролике Ильи Кантора](https://www.youtube.com/watch?v=5XZqeuWkQ4o&index=6&list=PLDyvV36pndZHfBThhg4Z0822EEG9VGenn). Используется плагин webpack.DefinePlugin. Вотчинг за изменениями JavaScript-файлов также лежит на плечах webpack. Также доступна горячая замена компонентов ([Hot module replacement](https://webpack.github.io/docs/hot-module-replacement.html)). На русском можно прочитать об этом на [habr'е](https://habrahabr.ru/company/Voximplant/blog/270593/) и посмотреть [ролики из скринкаста Ильи Кантора](https://www.youtube.com/watch?v=EQhXtTOxpVk&list=PLDyvV36pndZHfBThhg4Z0822EEG9VGenn&index=40). Данная возможность [опциональна](options.md#usehmr), реализована с помощью middleware для Browser-sync и плагина webpack.HotModuleReplacementPlugin. По умолчанию встроена поддежка babel (babel-loader) и eslint (eslint-loader), которые работают через webpack. Eslint использует встроенный парсер для разбора JavaScript-кода, но если вам необходимо поддерживать совсем новые фичи (экспериментальные), вам придется использовать парсер babel-eslint. Подробности можно прочесть в [репозитории проекта](https://github.com/babel/babel-eslint) и [документации eslint](http://eslint.org/docs/user-guide/configuring#specifying-parser-options). ================================================ FILE: docs/ru/options.md ================================================

English description | Описание на русском

# Опции Вся конфигураци сборщика находится в одном файле — tars-config.js в корне проекта. Нужно перезапустить сборку, чтобы изменения применились. ## Изменяемые опции ### postcss Type: `Array` Default: `[]` Example: ````javascript postcss: [ { name: 'postcss-short', options: { deny: ['text'] } }, { name: 'postcss-size', options: {} } ] ```` Здесь можно перечислить используемые постпроцессоры. Обязательно выполните установку используемых постпроцессоров. ### svg Type: `Object` Конфиг для работы с svg-графикой в TARS. #### active Type: `Boolean` Default: `true` Включение поддержки svg в проекте. #### workflow Type: `String` Default: `sprite` Способ работы с svg-графикой. Доступны SVG-спрайт и SVG-symbols. Поддерживаются значения `sprite` для использования SVG-спрайтов и `symbols` для svg-symbols. **При выборе "symbols", сборка для IE8 недоступна** #### symbolsConfig Type: `Object` Описывает конфиг для работы с svg-symbols. ##### loadingType Type: `String` Default: `inject` Устанавливает способ подключения svg-symbols на странице. Поддерживаются значения: * `inject` — инжект в тело HTML; * `separate-file` — хранение в отдельном файле; * `separate-file-with-link` — хранение в отдельном файле, при этом каждая иконка подключается из этого файла. ##### usePolyfillForExternalSymbols Type: `Boolean` Default: `true` Хранение в отдельном файле нативно поддерживается во всех современных браузерах, кроме IE9 - Edge. Для них используется полифл. Если вы не поддерживаете эти браузеры, то можете выставить false. ##### pathToExternalSymbolsFile Type: `String` Default: `''` Вы можете задать путь, по которому файл с svg-symbols будет находится в проекте. По умолчанию файл создается в корне готовой сборки. Пример значения: `static/images/`. ### css Type: `Object` Конфиг для работы с CSS в TARS. Доступен с версии TARS 1.8.0. #### workflow Type: `String` Default: `concat` Способ обработки CSS-кода. Доступны: * `concat` — конкатенация CSS-файлов в один в определенном порядке; * `manual` — использование точек входа (основных файлов), в которые импортируются файлы стилей проекта. ### js Type: `Object` Конфиг для работы с JavaScript в TARS. Доступен с версии TARS 1.7.0. #### workflow Type: `String` Default: `concat` Способ обработки JavaScript-кода. Доступны: * `concat` — конкатенация JavaScript-файлов в один в определенном порядке; * `modular` — использование бандлера, который будет разрешать зависимости между JavaScript-файлами. #### bundler Type: `String` Default: `webpack` В bundler можно указать используемый сборщик JavaScript-кода, если в качестве workflow был выбран `modular`. Пока что доступен только `webpack`. #### lint Type: `Boolean` Default: `true` Включение проверки ошибок в JavaScript-коде и code-style (опции для eslint находятся в корне, в файле `.eslintrc`. Весь список доступных опций можно найти [тут](http://eslint.org/)). Также, вы можете точечно отключить линтинг файлов используя `.eslintignore` в корне проекта. #### useBabel Type: `Boolean` Default: `false` Данная опция позволяет использовать [Babel](https://babeljs.io/) для поддержки ES6(ES7) синтаксиса. Конфиг для babel находит в корне проекта, в файле `.babelrc`. С доступными опциями .babelc можно ознакомится на [официальном сайте](https://babeljs.io/docs/usage/options/). Вам не нужно задавать опции 'filename' и все что связанно с 'sourcemaps', так как эти оцпии уже заданы в сборщике. #### webpack Type: `Object` Здесь можно управлять подключением особенных фич для webpack. ##### useHMR Type: `Boolean` Default: `false` Включение технологии горячей замены компонентов ([Hot module replacement](https://webpack.github.io/docs/hot-module-replacement.html)). ##### providePlugin Type: `Object` Default: `{}` Параметры для [Provide Plugin](https://webpack.github.io/docs/list-of-plugins.html#provideplugin). Автоматически загружаемые модули. #### removeConsoleLog Type: `Boolean` Default: `true` Удаление console.log, alert и debugger из JavaScript-файлов в сборке. Является опцией, так как иногда требуется оставить console.log в готовой сборке. #### jsPathsToConcatBeforeModulesJs и jsPathsToConcatAfterModulesJs Type: `Array of Strings` Default: `[]` Данная опция имеет смысл только при выборе concat в качестве workflow. В этом случае весь JavaScript-код проекта собирается в 1 файл, кроме javascript-файлов, которые находятся в директории separate-js. Если необходимо включить в сборку файлы из других мест (например, вы создали отдельную директорию для JavaScript-файлов), то можно прописать в эту опцию путь или массив путей (паттернов путей, типа controllers/\*\*/\*.js) до JavaScript-файлов, которые должны попасть в сборку до js-компонентов (jsPathsToConcatBeforeModulesJs) и JavaScript-файлов, которые должны быть подключены после JavaScript-файлов компонентов (jsPathsToConcatAfterModulesJs). Это будет полезно, при разработке сайта на JavaScript-фреймворке с какими-либо своими сущностями (контроллер, роутер и т.д.). Вам не требуется лезть в таски, просто создавайте отдельные директории, указывайте, за какими файлами следить. Также есть возможность отключить eslint для этих файлах (опции `lintJsCodeBeforeModules` и `lintJsCodeAfterModules`). ### sourcemaps Type: `Object` Default: ```javascript sourcemaps: { js: { active: true, inline: true }, css: { active: true, inline: true } }, ``` Конфиг для sourcemaps. Sourcemaps для js и css работают только в dev-режиме. active {Boolean}: использовать sourcemap или нет. inline {Boolean}: использовать встроенные сорсмапы или генерировать их отдельным файлом. ### notifyConfig Конфиг для модуля нотификаций. При включенных вотчерах, при изменениях в файлах проекта будут выдаваться системные уведомления, в которых будет указано, какой файл изменен, какой таск выполнен. Имеет вложенные опции. #### useNotify Type: `Boolean` Default: `true` Включение нотификации. Отключить нотификации можно с помощью переменных окружения: ```bash export DISABLE_NOTIFIER=true; #или export NODE_ENV=production; ``` Переменные окружения имеют больший вес и перезаписывают значение в tars-config.js #### title Type: `String` Default: `'TARS notification'` Каждая нотификация имеет тайтл. Если вы хотите видеть другой тайтл, то смело меняйте эту опцию. #### sounds Звуковые уведомления при нотификациях ##### onSuccess Type: `String, undefined` Default: `undefined` В данную опцию передается название системного звука, который будет звучать при нотификации, если сборка прошла успешно. Если звуков не нужно, то просто оставляйте `undefined`. ##### onError Type: `String, undefined` Default: `undefined` В данную опцию передается название системного звука, который будет звучать при нотификации, если сборка прошла с ошибками. Если звуков не нужно, то просто оставляйте `undefined`. ### minifyHtml Type: `Boolean` Default: `false` Включение минифицирования HTML. Если опция установлена в `false`, то скомпилированный HTML будет отформатирован. ### generateStaticPath Type: `Boolean` Default: `true` Включает построение относительного пути от текущей страницы до папки со статикой. В случае использования сервера, который будет раздавать статику (например, режим livereload) путь до статики не будет генерироваться, так как статика раздается сервером. ### devPath Type: `String` Default: `'./dev/'` В данную опцию передается строка с относительным или абсолютным путем к той папке, куда должен собираться проект в режиме разработки. Использование `/` после названия пути обязательно, чтобы не возникли проблемы с доступом к файлам. ### buildPath Type: `String` Default: `'./builds/'` В данную опцию передается строка с относительным или абсолютным путем к той папке, куда должен собираться проект. Если используется useBuildVersioning (использовать версионирование билдов), то каждый новый билд будет находится в отдельной папке с именем — версией билда, и каждая эта папка будет находится по пути, указанном в buildPath. Использование `/` после названия пути обязательно, чтобы не возникли проблемы с доступом к файлам. ### useBuildVersioning Type: `Boolean` Default: `true` Использовать версионирование билдов. Название версии состоит из имени билда + дата создания билда (точность до секунды). ### useArchiver Type: `Boolean` Default: `true` Создание архива с готовой версткой. Архив создается внутри папки с билдом. Если вы указали в файле package.json имя проекта, то имя архива будет взято оттуда, иначе по умолчанию будет 'build'. Также будет добавлена дата создания билда (точность до секунды). ### ulimit Type: `Number` Default: `4096` По умолчанию, число одновременно открытых файлов в ОС (Unix-системах) ограничено. Так как TARS работает на Gulp, то число одновременно открытых файлов может быть велико. Чтобы избежать проблем с этим, можно настроить [ulimit](http://ss64.com/bash/ulimit.html) (в нашем случае настраивается число одновременно открытых файлов). Если в проекте используется значительное число файлов и часть из них не попадает в конечную сборку, то просто увеличьте даную опцию. ## Частично изменяемые опции Данные опции можно менять только перед командой `init`, так как ни на какую команду они больше не влияют. Кроме `useImagesForDisplayWithDpi`, об этом подробнее ниже. ### templater Type: `String` Default: `handlebars` Options: `jade`, `pug`, `handlebars` В данной опции указывается используемый шаблонизатор. Доступны jade, pug и handlebars. В опцию передается название шаблонизатора с маленькой буквы. Если вы хотите писать на простом html, то оставьте опцию без изменений. ### cssPreprocessor Type: `String` Default: `scss` Options: `scss`, `sass`, `less`, `stylus` В данной опции указывается используемый css-препроцессор. Доступны scss, less или stylus. В опцию передается название css-препроцессора с маленькой буквы. ### useImagesForDisplayWithDpi Type: `Array` Default: `[96]` В данной опции указываются плотности пикселей различных экранов, которые будут поддерживаться вашим проектом. Поддерживаются значения: * 96 — 1 dppx (обычные экраны) * 192 — 2 dppx (ретина) * 288 — 3 dppx (например, nexus 5) * 384 - 4 dppx (например, nexus 6) На основе данной опции создаются папки для png-изображений различных размеров, для разных экранов. Подробнее в разделе [Работа с изображениями](images-processing.md). Данную опцию можно менять когда угодно, но есть пара важных моментов. Если вы меняете данную опцию перед командой `gulp|tars init`, то больше ничего делать не нужно. Если опция меняется потом, то необходимо руками создать (или удалить) директории в папке `static/img/sprite/`. Формат названия папки — значение опции + dpi. Например, `192dpi`. ### fs Опции для именования основных папок со статикой. Если вы меняете опции из этого блока перед командой `gulp|tars init`, то больше ничего делать не нужно. Если опция меняется потом, то необходимо руками переименовать соответствующие директории. #### staticFolderName Type: `String` Default: `'static'` Имя папки, в которой будет лежать статика проекта. Если вы только разрабатываете проект локально, то необходимо, чтобы значение этой опции совпадало со значением опции [staticPrefix](#staticPrefix) #### imagesFolderName Type: `String` Default: `'img'` Имя папки, в которой будут лежать картинки проекта. Чаще всего именно эта папка имеет различные значения, поэтому название этой директории опционально. #### componentsFolderName Type: `String` Default: `'components'` Имя папки, в которой будут лежать компоненты (модули для TARS версии 1.7.0 и ниже) проекта. ## Depricated ### useSVG **Опция больше не поддерживается, используйте svg.active** Type: `Boolean` Default: `true` Включение поддержки сборщиком svg-изображений. ### staticPrefixForCss **Опция больше не поддерживается, а значение задается в tars/tars.js** Type: `String` Default: `../imageFolderName/` Кастомный пути до папки со статикой из css-файлов. imageFolderName берется из опции [imagesFolderName](options.md#imagesFolderName) ### useJsLintAndHint **Опция была переименована в [lint](#lint) и находится в конфиге js.** ### autoprefixerConfig Какие еще браузеры доступны, можно глянуть [тут](https://github.com/postcss/autoprefixer#browsers). ~~**Опция была переннесена в plugins-config.json.**~~ **Опция была переннесена в .browserslistrc.** ### browserSyncConfig Конфиг для модуля Browsersync. Данный модуль реализует возможность livereload в браузере, расшаривание верстки во внешний веб, создание локального сервера. #### baseDir #### port #### open #### browser #### startUrl #### useNotifyInBrowser #### injectChanges **Опция была переннесена в plugins-config.json. На данный момент вы можете передать любую [опцию для browsersync](https://www.browsersync.io/docs/options/).** ### staticPrefix Значение данной опции задает значение плейсхолдеру %=static=% (__static__ или %=staticPrefix=% до версии TARS 1.6.0), который может использоваться в любых файлах проекта. **Опция больше не поддерживается, а значение задается в tars/tars.js** ================================================ FILE: docs/ru/plugins-options.md ================================================

English description | Описание на русском

# Конфигурирование плагинов В TARS версии 1.8.0 и выше появилась возможность конфигурировать почти все плагины (gulp-плагины и не только) в отдельном файле, plugins-config.json в корне проекта. Раньше для этого требовалось переопределять таск, в котором используется плагин, а иногда править файлы самого сборщика. Изменять можно 100% опций, но некоторые из плагинов должны быть настроены определенным образом, чтобы TARS работал корректно. Каждая такая опция описана в комментариях в plugins-config.json **Рекомендуется не менять их!** plugins-config.json — не просто json-файл. В нем вы можете использовать комментарии, и специальное выражение insert(). Об этом чуть подробнее. Некоторые конфиги зависят от текущего tars-config, например, base-dir для gulp-jade. Чтобы вам не приходилось менять это руками каждый раз при смене имени папки с компонентами, вы можете написать так: ```js "gulp-jade": { "pretty": true, "basedir": "markup/insert(tars.config.fs.componentsFolderName)" } ``` В этом случае, insert(tars.config.fs.componentsFolderName) будет заменено на то, что у вас находится в tars-config для componentsFolderName. Внутри insert() вы можете выполнить любую JavaScript функцию. **Важно обернуть insert() в кавычки сразу, чтобы JSON распарсился корректно. Не забудьте экранировать двойные кавычки, если они используются!** Пример с gulp-jade будет интерпретирован следующим образом: ```js "gulp-jade": { "pretty": true, "basedir": "markup/components" } Пару примеров использования insert(): ```js "example-plugin": { "option": "insert(function() {return 'tars'})" } ``` В итоге получим: ```js "example-plugin": { "option": "tars" } ``` ================================================ FILE: docs/ru/scenarios.md ================================================

English description | Описание на русском

# Сценарии использования Предполагается как минимум 3 сценария использования TARS. На самом деле вы можете придумать для себя свои. Основные будут перечислены тут: * Разработка с передачей в back-end для внедрения. * Разработка статического сайта локально. * Разработка статического сайта сразу готового к выкладке. Больше информации можно получить из [FAQ](faq.md). Во всех сценариях имеется в виду, что режим «разработка» (dev-таск) будет с любыми доступными ключами. ## Разработка с передачей в back-end для внедрения В данном случае, в tars-config важно выставить опцию minifyHtml в false. Также можно отключить removeConsoleLog (false), чтобы оставить все console.log без изменения. Возможно это может пригодиться внедряющей команде. В tars-config, в опции devPath, так-же есть возможность указать новый путь для интеграции с back-end частью проекта. Далее, для удобства версионирвоания сборок можно включить опцию useBuildVersioning и useArchiver, чтобы иметь в каждой папке со собранным проектом готовый к отправке архив. При сборке (build-таск) желательно не использовать ключ `--release`. Для проверки работоспособности минифицированных файлов можно использовать ключ `--min`. ## Разработка статического сайта локально В данном случае опция minifyHtml может быть любой, как вам удобно. Все остальные опции вы можете назначить как удобно, кроме useArchiver. Данную опцию рекомендуется отключить, чтобы не плодить ненужные архивы. При сборке (build-таск) желательно использовать ключ `--release`. ## Разработка статического сайта сразу готового к выкладке Все тоже самое, что и для «Разработка статического сайта локально». При сборке (build-таск) обязательно использовать ключ `--release`. ================================================ FILE: docs/ru/svg-processing.md ================================================

English description | Описание на русском

# Работа с SVG В TARS поддерживается два workflow для работы с векторной графикой: SVG-спрайт и SVG-symbols. Эти два подхода отличаются от остальных (инлайн в HTML, инлайн в CSS, base64, SVG-stack) почти 100%-й поддержкой во всех современных браузерах (начиная с IE9 включительно), кешируемостью, быстродействием и удобством работы. Вы можете использовать **только один тип работы** с SVG-графикой в проекте. Одновременно SVG-symbols и SVG-спрайт не поддерживаются. Вы можете указать все настройки проекта для работы с SVG-графикой в [конфигурационном файле проекта](options.md#svg). **Очень важно, чтобы при сохранении SVG-картинки в ней присутствовал атрибут viewBox! Сохраняйте SVG-картинку как объект, который может быть вставлен в HTML без изменений (в Adobe Illustrator это опция "Image location – Embed").** ## SVG symbols **При выборе этого workflow сборка для IE8 недоступна** В данном подходе SVG-изображения склеиваются в один общий SVG-файл, в котором каждая отдельная SVG-картинка представляется в виде [SVG-symbol](https://developer.mozilla.org/ru/docs/Web/SVG/Element/symbol). В этом случае вы можете переиспользовать каждую отдельную иконку несколько раз, задавать ей цвет (даже два) и размеры через CSS. Частично об этом подходе можно прочесть на [habrahabr.ru](https://habrahabr.ru/post/272505/) и в [западных источниках](https://css-tricks.com/svg-symbol-good-choice-icons/). Изображения, которые должны быть включены таким образом, необходимо складывать в папку (указан путь по умолчанию): `static/img/svg/`. Вложенность директорий **НЕ** поддерживается. Подключение этих иконок производится в шаблонах. В CSS можно лишь добавить цвета, размеры, заливку, цвет и толщину границ. Для подключения используются хелперы, которые генерируют весь необходимый HTML-код и атрибуты для подключения конкретной иконки. Подключение в Handlebars: ```handlebars {{Icon iconName='iconName' className='customClass' iconWidth='25' iconHeight='25'}} ``` Подключение в Jade: ```jade != jadeHelpers.Icon.call(locals, {iconName: 'iconName', className: 'customClass', iconWidth: '25', iconHeight: '25'}) ``` Подключение в Pug: ```jade != pugHelpers.Icon.call(locals, {iconName: 'iconName', className: 'customClass', iconWidth: '25', iconHeight: '25'}) ``` При подключении иконки вы можете задать два параметра: имя иконки (iconName), которая подключается (без расширения), имя класса (customClass), размеры (iconWidth, iconHeight). **Размеры можно не задавать, эти опции не обязательны и могут быть вычисленны автоматически**. Если имя класса не будет указано, то оно сгенерируется автоматически - по шаблону icon__iconName. Если не указаны размеры, то будут использованы размеры из svg файла. Иконки можно подключать как в шаблонах страниц, так и в компонентах. Данные хелперы сгенерируют следующий код: ```html ``` Файл с готовыми символами генерируется в TARS автоматически. Остается только подключить его. В TARS поддерживается несколько способов подключения SVG-symbols: * **inject** — инжект в тело HTML; * **separate-file-with-link** — хранение в отдельном файле, при этом каждая иконка подключается из этого файла; * **separate-file** — хранение в отдельном файле. В случае инжекта в use указывается только ID иконки (ее имя). Вы можете управлять, куда именно инжектить SVG-symbols с помощью шаблона %=symbols=%, который по умолчанию присутствует в шаблоне - если вы используете оригинальную версию TARS. **Нет необходимости удалять эти метки, а также подключение различных полифилов или скриптов для старых браузеров, так как они будут автоматически удалены из готовой сборки, если они не используются!** В случае хранения в отдельном файле с подключением из него, к ID иконки добавляется **полный путь** до этого файла. ```html ``` В этом случае SVG-symbols кешируется браузером. При этом вы можете задать путь, по которому файл с SVG-symbols будет находится в проекте, с помощью опции pathToExternalSymbolsFile в конфигурационном файле проекта. По умолчанию файл создается в корне готовой сборки. Данный способ нативно поддерживается во всех современных браузерах, кроме IE9 - Edge. Для них в TARS предусмотрен полифил. Вы можете его не включать в сборку, если не поддерживаете IE. Код подключения полифила по умолчанию присутствует в шаблоне, если вы используете оригинальную версию TARS. **Нет необходимости удалять эти метки, а также подключение различных полифилов или скриптов для старых браузеров, так как они будут автоматически удалены из готовой сборки, если они не используются!** Третий способ подразумевает, что вы сами реализуете подключение SVG-symbols в шаблон. Вам необходимо будет написать код, который загрузит файл SVG-symbols и вставит его в код страницы. Наиболее интересные подходы описаны на [css-tricks](https://css-tricks.com/ajaxing-svg-sprite/) и [osvaldas.info](http://osvaldas.info/caching-svg-sprite-in-localstorage). Последний способ один из самых эффективных. Как использовать тот или иной тип подключения SVG-symbols вы можете узнать из [документации о конфиге проекта](options.md#svg). ## SVG-спрайты В данном подходе SVG-изображения склеиваются в один SVG-спрайт. SVG-изображения в release-версии минифицируются и к нему добавляется hash в название. Изображения, которые должны быть включены таким образом, необходимо складывать в папку (указан путь по умолчанию): `static/img/svg/`. Вложенность директорий **НЕ** поддерживается. Подключение SVG-спрайта производится с помощью миксина (пример на SCSS): ```scss @include bg-svg($svg-image-name); // Подключение svg-изображения ``` Обратите внимание, что в миксин передается **переменная** с именем исходной картинки (без расширения). Миксин `bg-svg` в CSS подключит SVG-спрайт в качестве фона, задаст все необходимые смещения и размеры. Если сборка выполнена с ключом `--ie` или `--ie8`, то будет создан спрайт с растрированными векторными изображениями. Вам не нужно думать о том, как это будет работать в IE8, так как TARS все сделает за вас. В данном подходе вы не сможете задать цвет SVG-изображения через CSS. Необходимо, чтобы SVG-картинка уже была полностью готова к использованию, прежде чем она попадет в спрайт. ================================================ FILE: docs/ru/tasks-and-watchers.md ================================================

English description | Описание на русском

# Работа с тасками и вотчерами TARS – набор gulp-тасков, организованных особым образом. Каждый таск — отдельный файл (кроме составных, таких как build, dev и т.п.), в котором описывается последовательность действий над набором файлов. Также в TARS присутствуют вотчеры, которые позволяют запускать таски при изменении какого-либо файла. Таски и вотчеры бывают системные (встроенные в TARS по умолчанию) и пользовательские, с помощью которых можно расширить функциональность TARS. В общем виде работа TARS в режиме разработки выглядит следующим образом: * при запуске запускаются все таски, которые требуются для сборки проекта; * после сборки запускаются вотчеры, которые будут следить за изменениями файлов и запускать определенные таски. Встроенные таски находятся в `tars/tasks`, разбиты по папкам в зависимости от типа таска. Встроенные вотчеры для тасков находятся в `tars/watchers`. Вы можете добавлять любые свои таски/вотчеры и размещать их в `tars/user-tasks`/`tars/user-watchers`. При добавлении тасков и вотчеров рекомендуется использовать: * tars.config.fs.staticFolderName — для имени папки со статикой; * tars.config.fs.imagesFolderName — для имени папки с изображениями; * tars.templater.ext – содержит расширения для файлов выбранного шаблонизатора; * tars.cssPreproc.ext – содержит расширения для файлов выбранного css-препроцессора. Если вам требуется заменить какой-либо встроенный таск/вотчер, вам необходимо назвать его также, как тот таск/вотчер, который необходимо заменить. Важно соблюсти вложенность папок. Пример, справедливый как для тасков, так и для вотчеров, доступен вот такой встроенный таск: ``` tars/tasks/html/minify-html.js ``` Необходимо, чтобы вместо встроенного `minify-html.js` подключался пользовательский. Для этого необходимо в папке `user-tasks` повторить ту же файловую структуру для файла таска и использовать такое же имя для самого таска: ``` tars/user-tasks/html/minify-html.js ``` В этом случае в gulpfile.js будет подключен не встроенный, а пользовательский таск. Также есть возможность отключить любой таск/вотчер, просто добавив знак `_` в начало названия этого таска/вотчера. Если вам требуется встроить пользовательский таск в уже существующую цепочку других тасков, например необходимо выполнять вашу задачу в рамках dev-таска, то необходимо переопределить dev-таск, указав именно ту цепочку задач, которая подойдет именно вам. Больше подробностей вы можете получить в соответствующих разделах документации о [тасках](tasks.md) и [вотчерах](watchers.md). ================================================ FILE: docs/ru/tasks.md ================================================

English description | Описание на русском

# Таски в TARS Каждый таск представляет из себя [commonJS-модуль](http://wiki.commonjs.org/wiki/Modules/1.1). Все таски включаются в gulpfile в корне проекта автоматически. По умолчанию в gulpfile.js находятся только ссылки на основные таски, например, build ссылается на main:build. Таким образом вы сможете переопределить абсолютно любой таск, совсем не влезая в структуру сборщика. Свои таски можно создавать в директории user-tasks. По умолчанию там уже находится пример таска. Вообще, в TARS можно подключить любой gulp-task. По умолчанию каждому таску требуется набор модулей для корректной работы: ```javascript const gulp = tars.packages.gulp; const gutil = tars.packages.gutil; const notifier = tars.helpers.notifier; ``` Также, если требуется использовать livereload для данного таска, подключаем модуль browserSync: ```javascript const browserSync = tars.packages.browserSync; ``` Если требуются какие-либо еще зависимости, подключаем их тут же. При этом, зависимости, которых нет в основном package.json, можно занести в user-package.json, который находится в корне проекта. Формат такой же, как и у основного package.json **Не помещайте свои собственные зависимости в package.json. Помещайте их user-package.json** Исключением здесь может быть использование TARS-CLI. При инициализации проекта с помощью TARS-CLI и стандартного архива с TARS (из текущего репозитория) user-package.json не создается в папке с проектом. Вместо него будет обычный package.json TARS-CLI позволяет [инициализировать TARS с помощью любого zip-архива с TARS](https://github.com/tars/tars-cli#tars-init). Если вам необходимо, чтобы в package.json уже были какие-либо пакеты, то в вашем форке TARS занесите все пользовательские зависимости в user-package.json и они автоматом окажутся в package.json нового проекта при инициализации с помощью TARS-CLI. Данная функциональность доступна для TARS-CLI начиная с версии 1.1.8. После подключения зависимостей идет тело модуля, который будет экспортировать таск. Каждый таск описывается внутри экспортируемой функции. Во всех тасках и вотчерах досутпен глобальный объект tars, в котором находятся все данные, конфиги и т.д. текущего проекта. Экспортируемая функция возвращает полноценный gulp-таск. Далее делаем все как и с обычным таском для gulp. Если требуется нотификация, то таск должен оканчиваться следующим образом: ```javascript // If you need to reload browser, uncomment the row below // .pipe(browserSync.reload({stream:true})) .pipe( notifier('Example task is finished \n') ); ``` В notifier передается строка, которая будет показываться в уведомлениях. Также можно вызвать callback, или вернуть основной поток, если требуется выполнять таски в определенном порядке. Более подробно [здесь](http://frontender.info/handling-sync-tasks-with-gulp-js). Может показаться, что в некоторых местах есть излишний код, есть обращения к файлам, а не потокам. Такие места есть, но это сделано в угоду модульности и легкой расширяемости. На самом деле, на скорость работы сборщика именно эти места не влияют. ================================================ FILE: docs/ru/update-guide.md ================================================

English description | Описание на русском

# Руководство по обновлению TARS **С версии TARS 1.5.0 доступно автоматическое обновление проекта с помощью TARS-CLI. Вам больше не потребуется делать это вручную! Подробности можно прочитать [в документации TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/ru/update-actions.md). При использовании CLI, не нужно выполнять операции, описанные ниже!** В рамках мажорной версии (1.\*.\*, например) можно переносить папку markup (папка, в которой должны находиться исходники вашего проекта), в любую версию. В любой версии в рамках одной мажорной сборка пройдет успешно. Данное утверждение справедливо для TARS выше (и включая) версии 1.2.0. До 1.2.0 были небольшие изменения в файловой структуре и способе подключения компонентов в Handlebars. Все изменения доступны в [changelog](changelog.md). Таким образом, чтобы получить новую функциональность, которая вышла в новой минорной версии (\*.4.\*, например) достаточно: * [скачать новый TARS](https://github.com/tars/tars/archive/master.zip); * проинициализировать его с теми настройками, которые есть в вашем текущем проекте; * перенести папку markup из текущего проекта в новый TARS; * поправить конфиги, если это необходимо. После этого вы можете спокойно использовать новые фичи. Подробнее о системе версионирования можно прочитать [здесь](http://semver.org/lang/ru). **Повторюсь, с версии TARS 1.5.0 доступно автоматическое обновление проекта с помощью TARS-CLI. Вам больше не потребуется делать это вручную! Подробности можно прочитать [в документации TARS-CLI](https://github.com/tars/tars-cli/blob/master/docs/ru/update-actions.md)** Есть исключение из этого правила. Например, была добавлена работа с coffee-файлами в одной из минорных версий. Если ваш проект использует только JavaScript, то вы также можете использовать любую минорную версию в рамках мажорной. Если вы хотите использовать coffee-файлы, то необходимо выбирать только ту версию, в которой были добавлены таски для работы с ними или версию выше. В основном [readme](../README_RU.md) обязательно указано, с какой версии есть доступ к той или иной функциональности. Также, если вы вносили изменения в файлы сборщика (что угодно еще, кроме папки markup), то необходимо эти изменения перенести вручную. Все последние изменения доступны по ссылке: [История изменений](changelog.md). Для перехода от одной мажорной версии к другой будет написано соответствующее руководство. ================================================ FILE: docs/ru/watchers.md ================================================

English description | Описание на русском

# Вотчеры в TARS Как и таски, вотчеры представляют из себя [commonJS-модуль](http://wiki.commonjs.org/wiki/Modules/1.1). Все вотчеры включаются в gulpfile в корне проекта автоматически. Свои вотчеры можно создавать в директории user-watchers. По умолчанию там уже находится пример вотчера. Разберем его подробнее. По умолчанию каждому вотчеру требуется набор модулей для корректной работы: ```javascript const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const gutil = tars.packages.gutil; const chokidar = tars.packages.chokidar; const watcherLog = tars.helpers.watcherLog; ``` ```javascript return chokidar.watch( /* String of path pattern or array of strings */, Object.assign(tars.options.watch, { // Options set bellow will override default from tars.options.watch // If you need default options, you can use just tars.options.watch ignored: /* String of path pattern or array of strings to ignore. If nothing to igonre — just set it to ''*/, persistent: /* Boolean, true by default*/, ignoreInitial: /* Boolean, true by default*/ }) ).on('all', function(event, path) { watcherLog(event, path); // You could start as many tasks as you need runSequence(/* Task name (String) to start */); }); ``` В chokidar.watch можно передать паттерн или массив паттернов путей до файлов, за которыми нужно следить. После паттернов передаются опции для chokidar. Если вам подходят опции по умолчанию, просто передайте вторым аргументом в chokidar.watch tars.options.watch. Если какие-либо свойства необходимо переопределить, используйте [Object.assign](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Object/assign). Первым параметром assign принимает то, чем мы будем переопределять, а вторым — что будем переопределять. В опцию ignored можно передать паттерн или массив паттернов путей до файлов, которые нужно отфильтровать от слежки в рамках данного вотчера. В gulp.start передается имя таска, который необходимо запустить при изменениях в файлах, за которыми следит данный вотчер. По умолчанию вотчер срабатывает на все операции с файлами (удаление, создание, переименовывание). Можно изменить это поведение, поменяв .on('all', function(event, path) all на нужное событие. Список доступных событий можно узнать в [документации к chokidar](https://github.com/paulmillr/chokidar#getting-started). ================================================ FILE: gulpfile.js ================================================ 'use strict'; // Tars main-module init // It is a global var require('./tars/tars'); const gulp = tars.packages.gulp; // Require system and user's tasks // You can add your own tasks. // All your tasks have to be in tars/user-tasks folder tars.helpers.tarsFsHelper.getTasks().forEach((file) => require(file)()); // Register links to main tasks without namespace // Build-dev task. Build dev-version (without watchers) gulp.task( 'build-dev', gulp.series('main:build-dev', (done) => done()), ); // Dev task. Build dev-version with watchers and livereload gulp.task( 'dev', gulp.series('main:dev', (done) => done()), ); // Build task. Build release version gulp.task( 'build', gulp.series('main:build', (done) => done()), ); // Init task. Just start init task gulp.task( 'init', gulp.series('service:init', (done) => done()), ); // Update-deps task. Just start update-deps task gulp.task( 'update-deps', gulp.series('service:update-deps', (done) => done()), ); // Default task. Just start build task gulp.task( 'default', gulp.series('build', (done) => done()), ); ================================================ FILE: markup/components/_template/_template.js ================================================ ================================================ FILE: markup/components/_template/data/data.js ================================================ /* Module data structure */ // moduleName: { // dataType: { // property: value // } // } /* Module data example */ _template: { big: { title: 'Hello world', age: 10, button: false } } ================================================ FILE: markup/static/js/main.js ================================================ 'use strict'; /* This file can be used as entry point for webpack! */ ================================================ FILE: markup/static/misc/humans.txt ================================================ # humanstxt.org/ # The humans responsible & technologies # TEAM -- -- # THANKS # TECHNOLOGIES HTML5, CSS3, JS ================================================ FILE: package.json ================================================ { "name": "tars", "version": "1.15.1", "engines": { "node": "^16.x.x" }, "os": [ "darwin", "linux", "win32" ], "description": "Powerfull markup builder", "main": "gulpfile.js", "dependencies": { "@babel/core": "^7.5.5", "@babel/preset-env": "^7.5.5", "babel-loader": "^8.0.6" }, "devDependencies": { "autoprefixer": "^9.7.3", "browser-sync": "^2.26.7", "chokidar": "^3.3.1", "comment-json": "^2.4.1", "del": "^5.1.0", "download": "4.4.3", "eslint": "^6.8.0", "eslint-loader": "^3.0.3", "gulp": "^4.0.2", "gulp-babel": "^8.0.0", "gulp-cached": "^1.1.1", "gulp-changed": "^4.0.2", "gulp-compile-handlebars": "0.6.1", "gulp-concat": "2.6.1", "gulp-csso": "^4.0.1", "gulp-data": "^1.3.1", "gulp-eslint": "^6.0.0", "gulp-html-prettify": "https://github.com/artem-malko/gulp-html-prettify/archive/master.tar.gz", "gulp-htmlmin": "^5.0.1", "gulp-if": "^3.0.0", "gulp-imagemin": "6.2.0", "gulp-importify": "^0.0.7", "gulp-jade": "1.1.0", "gulp-jade-inheritance": "https://github.com/tars/gulp-jade-inheritance/archive/master.tar.gz", "gulp-less": "3.5.0", "gulp-minify-html": "^1.0.6", "gulp-notify": "^3.2.0", "gulp-plumber": "^1.2.1", "gulp-postcss": "^8.0.0", "gulp-pug": "^4.0.1", "gulp-pug-inheritance": "https://github.com/artem-malko/gulp-pug-inheritance/archive/master.tar.gz", "gulp-rename": "^1.4.0", "gulp-replace-task": "0.11.0", "gulp-sass": "^5.1.0", "gulp-sourcemaps": "^1.6.0", "gulp-stylus": "^2.7.0", "gulp-svg-spritesheet": "https://github.com/artem-malko/gulp-svg-spritesheet/archive/master.tar.gz", "gulp-svg-symbols": "https://github.com/artem-malko/gulp-svg-symbols/archive/master.tar.gz", "gulp-svg2png": "1.0.2", "gulp-terser": "^1.2.0", "gulp-uglify": "^3.0.2", "gulp-util": "3.0.8", "gulp-zip": "^5.0.0", "gulp.spritesmith": "^6.10.1", "gulp4-run-sequence": "^1.0.0", "mkdirp": "^0.5.1", "ncp": "^2.0.0", "run-sequence": "^2.2.1", "sass": "^1.49.9", "source-map-loader": "^0.2.4", "stream-combiner": "^0.2.2", "terser-webpack-plugin": "1.4.1", "through2": "^3.0.1", "uglifyjs-webpack-plugin": "2.2.0", "webpack": "^4.39.1", "webpack-dev-middleware": "^3.7.0", "webpack-hot-middleware": "^2.25.0" }, "optionalDependencies": { "fsevents": "^2.0.7", "posix": "^4.2.0" }, "scripts": { "install": "node ./tars/helpers/install-additional-deps.js", "lint": "eslint webpack.config.js tars/*.js tars/tasks/**/*.js tars/watchers/**/*.js tars/helpers/**/*.js gulpfile.js --rule 'valid-jsdoc: [0, {}]'" }, "repository": { "type": "git", "url": "https://github.com/tars/tars.git" }, "author": "Artem Malko", "license": "MIT", "bugs": { "url": "https://github.com/tars/tars/issues" }, "homepage": "https://github.com/tars/tars", "keywords": [ "gulp", "makeup", "markup" ] } ================================================ FILE: plugins-config.json ================================================ { // You can find docs for this file here: ./docs/en|ru/plugins-options.md "browserSync": { "startPath": "/index.html", "server": { "baseDir": "./dev" }, "port": 3004, "open": true, "notify": true, // Choose browser to open // @type {String|Array} // Example: ['google chrome', 'firefox'] // Avalible: safari, internet explorer, google chrome, firefox, opera "browser": "default", "injectChanges": false }, "gulp-sass": { "outputStyle": "expanded", "includePaths": ["./", "./markup/", "./node_modules/", "./bower_components/"] }, "gulp-less": { "paths": ["./", "./markup/", "./node_modules/", "./bower_components/"] }, "gulp-stylus": { "resolve url": true, "include css": true, "include": ["./", "./markup/", "./node_modules/", "./bower_components/"] }, // helpers option is set in make-sprite-for-svg. // It is strongly recommended to not override it! "gulp-compile-handlebars": { "batch": ["./markup/insert(tars.config.fs.componentsFolderName)"] }, // locals option is set in ./tars.js "gulp-pug": { "pretty": true, "basedir": "markup/insert(tars.config.fs.componentsFolderName)" }, // locals option is set in ./tars.js "gulp-jade": { "pretty": true, "basedir": "markup/insert(tars.config.fs.componentsFolderName)" }, "gulp-csso": { "restructure": true }, // cssPathSvg, templateSrc, templateDest and imgName is set in make-sprite-for-svg. // It is strongly recommended to not override these options! "gulp-svg-spritesheet": { "padding": 4 }, "gulp.spritesmith": { // Config for spritesmith in task make-fallback-for-svg // imgName, cssName, cssTemplate is set in task. // It is strongly recommended to not override these options! "svg-fallback": { "algorithm": "binary-tree", "padding": 4 }, // Config for spritesmith in task make-sprite // imgName, cssName, cssTemplate is set in task. // It is strongly recommended to not override these options! "regular-raster-sprite": { "algorithm": "binary-tree", "padding": 4 } }, // This config can be overrided by user-tasks/html/helpers/modify-options "gulp-htmlmin": { "minifyCSS": true, "minifyJS": true, "collapseWhitespace": true, "conservativeCollapse": true, "collapseInlineTagWhitespace": true, "removeRedundantAttributes": true, "removeStyleLinkTypeAttributes": true }, // This config can be overrided by user-tasks/html/helpers/modify-options "gulp-html-prettify": { "indent_char": " ", "indent_size": 4, "indent_inner_html": true }, "gulp-terser": { "mangle": false, "compress": { "drop_console": "insert(tars.config.js.removeConsoleLog)", "drop_debugger": "insert(tars.config.js.removeConsoleLog)" } } } ================================================ FILE: prettier.config.js ================================================ module.exports = { singleQuote: true, trailingComma: 'all', arrowParens: 'always', printWidth: 110, semi: true, }; ================================================ FILE: tars/helpers/filter-files-by-path.js ================================================ 'use strict'; const through2 = tars.packages.through2; /** * Filter files in pipe via it's path */ module.exports = function filterFilesByPath(patterns) { const patternsToCheck = [].concat(patterns); return through2.obj(function (file, enc, callback) { const filePath = file.path.replace(/\\/g, '/'); let checkStatus = true; patternsToCheck.forEach(pattern => { if (pattern.test(filePath)) { checkStatus = false; } }); if (checkStatus) { this.push(file); // eslint-disable-line no-invalid-this } return callback(); }, callback => callback()); }; ================================================ FILE: tars/helpers/get-templater-name.js ================================================ 'use strict'; /** * Get correct templater name * @return {string} Templater name */ module.exports = function getTemplaterName(templaterNameFromConfig) { switch (templaterNameFromConfig) { case 'handelbars': case 'handlebars': case 'hdb': case 'hb': return 'handlebars'; case 'jade': return 'jade'; case 'pug': default: return 'pug'; } }; ================================================ FILE: tars/helpers/install-additional-deps.js ================================================ 'use strict'; // It is a global var require('../tars'); const exec = require('child_process').exec; let usersDeps; try { usersDeps = require(process.cwd() + '/user-package'); } catch (error) { if (error.code !== 'MODULE_NOT_FOUND') { console.error('User-package.json is not valid!\n'); console.error(error.stack); } else { console.log('User-package.json is not exist. Additional deps won\'t be installed.'); console.log('It is not an Error, it is just warning!'); } } /* eslint-disable no-loop-func */ if (usersDeps && usersDeps.dependencies) { for (let dep in usersDeps.dependencies) { if (dep) { exec('npm i ' + dep + '@' + usersDeps.dependencies[dep], (error, stdout, stderr) => { if (error) { console.log(stderr); } else { console.log(stdout); } }); } } } /* eslint-enable no-loop-func */ ================================================ FILE: tars/helpers/modify-date-formatter.js ================================================ 'use strict'; /** * Date formatter for Gulp notify. It showes only hours, minutes and seconds * @param {number} timeItem hours, minutes or seconds * @return {string} String with formatted time */ function formatTime(timeItem) { if (timeItem < 10) { timeItem = '0' + timeItem; } return timeItem; } module.exports = { /** * Get time of last modify of something (css, js and etc) * @return {string} String with formatted time */ getTimeOfModify() { const currentDate = new Date(); const hours = currentDate.getHours(); const minutes = currentDate.getMinutes(); const seconds = currentDate.getSeconds(); return formatTime(hours) + ':' + formatTime(minutes) + ':' + formatTime(seconds); } }; ================================================ FILE: tars/helpers/notifier.js ================================================ 'use strict'; const notify = tars.packages.notify; const gutil = tars.packages.gutil; const notifyConfig = tars.config.notifyConfig; const path = require('path'); function cutUselessLog(error) { return error.message.replace(/(at\sParser\.pp\.raise[\s\S]*)/, ''); } /** * Notify helper */ module.exports = { /** * On error notifier * @param {String} message Error message * @param {Error} error Error object * @return {Pipe} */ error(message, error, params) { message = message || 'Something is happen while working.'; error = error || new Error(); params = params || {}; const resultMessage = '\n' + message + '\nLook in the console for details.\n'; if (!(error instanceof(Error))) { error = new Error(error); } if (process.env.NODE_ENV !== 'production' && !process.env.DISABLE_NOTIFIER) { notify.onError({ sound: notifyConfig.sounds.onError, title: notifyConfig.title, message: resultMessage, icon: path.resolve(tars.root + '/icons/tars_error.png'), onLast: true })(error); } else { console.error(gutil.colors.red(message + '\n')); } if (error.message) { console.log(gutil.colors.underline.red('Error details:\n')); console.error(cutUselessLog(error)); console.log(gutil.colors.red('_______________\n')); } return tars.packages.gutil.noop(); }, /** * On success notifier * @param {String} message Success message * @param {Boolean} onLast Use notify only on last changed file * @return {Pipe} */ success(message, params) { if (notifyConfig.useNotify && tars.options.notify && process.env.NODE_ENV !== 'production') { params = params || {}; const defaultConfig = { sound: notifyConfig.sounds.onSuccess, title: notifyConfig.title, templateOptions: { date: tars.helpers.dateFormatter.getTimeOfModify() }, icon: path.resolve(tars.root + '/icons/tars.png') }; let resultMessage = message + '\n' || 'Task\'ve been finished\n'; resultMessage += notifyConfig.taskFinishedText + '<%= options.date %>'; if (params.notStream) { return notify(defaultConfig).write(resultMessage); } return notify( Object.assign( defaultConfig, { onLast: params.onLast || true, message: resultMessage } ) ); } return tars.packages.gutil.noop(); } }; ================================================ FILE: tars/helpers/plugins-config-processing.js ================================================ 'use strict'; const json = tars.require('comment-json'); const fs = require('fs'); const cwd = process.cwd(); /** * Execute function insert() in plugins-config.json */ module.exports = function makePluginsConfig() { const rawPluginsConfig = json.parse(fs.readFileSync(`${cwd}/plugins-config.json`).toString()); const stringifiedPluginsConfig = json.stringify(rawPluginsConfig, null, 2); const processedPluginsConfig = stringifiedPluginsConfig.replace( /insert\(([\w.\-()`\{\/}$\s]+)\)/gi, (match, p1) => eval(p1) ); return json.parse(processedPluginsConfig); }; ================================================ FILE: tars/helpers/set-build-version.js ================================================ 'use strict'; /** * Generate build version * @return {String} build version */ module.exports = function setBuildVersion() { // build version is current date without spaces (replaced to _) and without time zone info. return '_ver-' + new Date() .toString() .replace(/\s\w+\+.*/, '') .replace(/\s|:/g, '_'); }; ================================================ FILE: tars/helpers/set-ulimit.js ================================================ 'use strict'; /** * Set ulimit to tars.config.ulimit * @return {Boolean} */ module.exports = function setUlimit() { const limit = tars.config.ulimit; let posix; try { posix = require('posix'); } catch (ex) { return false; } if (posix) { try { posix.setrlimit('nofile', { soft: limit }); return true; } catch (ex) { console.log('Error while ulimit setting'); return false; } } return false; }; ================================================ FILE: tars/helpers/skip-task-with-empty-pipe.js ================================================ 'use strict'; const through2 = tars.packages.through2; /** * Skip task if there are no any files in pipe * @param {String} taskName The name of task to skip * @param {Callback} skipCallback Callback for task skipping * @return {Object} Pipe */ module.exports = function skipTaskWithEmptyPipe(taskName, skipCallback) { let filesCount = 0; return through2.obj(function (file, enc, callback) { if (!file.isNull()) { filesCount++; } this.push(file); // eslint-disable-line no-invalid-this return callback(); }, (continueCallback) => { if (filesCount) { return continueCallback(); } else { tars.skipTaskLog(taskName, 'No files were passed'); return skipCallback(); } }); }; ================================================ FILE: tars/helpers/start-screen-generator.js ================================================ 'use strict'; /** * Output in the begining * @param {Object} gutil Utils for gulp */ module.exports = gutil => { const currentCommand = process.argv.slice(2)[0]; const silentCommands = ['init', 're-init', 'update-deps']; const usedFlagsArray = Object.keys(tars.flags); // Do not show if command was init, re-init or update-deps if (silentCommands.indexOf(currentCommand) > -1) { return; } // Log warning, if it is not CLI-mode if (!tars.cli) { if (tars.isDevMode) { console.log(gutil.colors.yellow.inverse('\n----------------------------------------------------------------------')); tars.say(gutil.colors.red.bold('You\'ve started TARS via gulp.')); tars.say(gutil.colors.red.bold('This mode is depricated for developing.')); tars.say(gutil.colors.red.bold('Please, do not use "dev" tasks in with mode.\n')); tars.say('Install tars-cli for developing.'); tars.say('Run the command ' + gutil.colors.cyan('"npm i -g tars-cli"') + ', to install tars-cli.'); tars.say('More info: https://github.com/tars/tars-cli.'); console.log(gutil.colors.yellow.inverse('\n----------------------------------------------------------------------')); } console.log('\n----------------------------------------------------------------------------'); tars.say('Build have been started. You are using:\n'); if (tars.flags.release) { tars.say('• release mode;'); } if (tars.flags.min) { tars.say('• minify mode;'); } if (tars.flags.lr) { tars.say('• livereload mode;'); } if (tars.flags.tunnel) { tars.say('• tunnel mode;'); } if (tars.flags.ie8 || tars.flags.ie) { tars.say('• ie8 maintenance;'); } if (tars.flags.ie9 || tars.flags.ie) { tars.say('• ie9 maintenance;'); } if (usedFlagsArray.length === 1) { tars.say(gutil.colors.black.bold('No modes.')); } console.log('\n'); tars.say('Have a nice work!'); tars.say('Please wait for a moment, while I\'m preparing builder for working...'); console.log('----------------------------------------------------------------------------\n'); } }; ================================================ FILE: tars/helpers/string-helper.js ================================================ 'use strict'; /** * Helper for watcher logging * @param {String} event Type of event * @param {String} path Path of changed file */ module.exports = { /** * Capitalize first letter of a string * @param {String} str String to modify * @return {String} String, with the first letter capitalized */ capitalizeFirstLetter(str) { str = str && String(str) || ''; return str.charAt(0).toUpperCase() + str.substr(1); } }; ================================================ FILE: tars/helpers/tars-fs-helper.js ================================================ 'use strict'; const fs = require('fs'); const path = require('path'); /** * Check, that file is task or watcher * All files with * 1) "example-" in name or path; * 2) "/helpers/" in path; * 3) start from _ char; * All that files won't be used * @param {String} pathToFile Path to file to check * @param {String} file File to check * @return {Boolean} Is file task or watcher */ function isValidFile(pathToFile, file) { return !pathToFile.match(/example-|[\/\\]helpers[\/\\]/i) && !file.match(/^_/) && pathToFile.match(/js$/i); } /** * Get hashmap of files and path to that files * @param {String} dir Folder to read * @return {Object} Hashmap of files and paths to that files */ function getFilesFromDir(dir) { const list = fs.readdirSync(dir); let results = {}; list.forEach(file => { const fullPathToFile = dir + '/' + file; const stat = fs.statSync(fullPathToFile); if (stat && stat.isDirectory()) { results = Object.assign(results, getFilesFromDir(fullPathToFile)); } else { if (isValidFile(fullPathToFile, file)) { results[path.parse(dir).name + '/' + file] = fullPathToFile; } } }); return results; } /** * Merge two objects from arguments and make array from ready object * @param {Object} systemItems System tasks/watchers * @param {Object} usersItems User's tasks/watchers * @return {Array} Array of unique system/user's tasks/watchers */ function getReadyUniqueItemsArray(systemItems, usersItems) { const uniqueItems = Object.assign(systemItems, usersItems); return Object.keys(uniqueItems).map(key => uniqueItems[key]); } module.exports = { /** * Get paths to all tasks, user's and system * @return {Array} Array of unique system/user's tasks */ getTasks() { const systemTasks = getFilesFromDir(tars.root + '/tasks'); const userTasks = getFilesFromDir(tars.root + '/user-tasks'); const readyTasksArray = getReadyUniqueItemsArray(systemTasks, userTasks); return readyTasksArray; }, /** * Get paths to all watchers, user's and system * @return {Array} Array of unique system/user's watchers */ getWatchers() { const systemWatchers = getFilesFromDir(tars.root + '/watchers'); const userWatchers = getFilesFromDir(tars.root + '/user-watchers'); const readyWatchersArray = getReadyUniqueItemsArray(systemWatchers, userWatchers); return readyWatchersArray; } }; ================================================ FILE: tars/helpers/watcher-log.js ================================================ 'use strict'; const gutil = tars.packages.gutil; /** * Helper for watcher logging * @param {String} event Type of event * @param {String} path Path of changed file */ module.exports = (event, path) => { gutil.log('File: ' + gutil.colors.green.bold(path) + ' Event: ' + gutil.colors.green.bold(event)); }; ================================================ FILE: tars/tars.js ================================================ 'use strict'; /** * Main module for TARS */ /** * Reqiure node-modules from TARS-CLI, if tars was executed via CLI and from local node_modules instead * @param {String} packageName Name of the required package * @return {Object} Required package */ function tarsRequire(packageName) { // Log for TARS debug if (process.env.TARS_DEBUG) { console.log('Module required: ', packageName); } if (process.env.npmRoot) { try { return require(process.env.npmRoot + packageName); } catch (error) { const util = require('util'); console.log('\n'); util.inspect.styles.string = 'red'; console.log('---------------------------------------------------------------------------------'); console.dir('It seems, that TARS in current project is not compatible with current TARS-CLI!', { colors: true, }); console.dir(`Package "${packageName}" is not available.`, { colors: true, }); console.dir('Update TARS-CLI via "tars update" and your project via "tars update-project"', { colors: true, }); console.dir('Please, write to the tars.builder@gmail.com, if update did not help you.', { colors: true, }); console.log( '---------------------------------------------------------------------------------\n', ); throw new Error(`Package ${packageName} is not available.`); } } return require(packageName); } // TARS is a global var global.tars = { require: tarsRequire, cli: process.env.npmRoot ? true : false, root: __dirname, packageInfo: require('../package.json'), config: require('../tars-config'), }; const gutil = tars.require('gulp-util'); const os = require('os'); const helpersDirPath = './helpers'; const cssPreprocName = tars.config.cssPreprocessor.toLowerCase(); const templaterName = require(helpersDirPath + '/get-templater-name')(tars.config.templater.toLowerCase()); const buildVersion = require(helpersDirPath + '/set-build-version')(); const useBuildVersioning = tars.config.useBuildVersioning; // Config for plugins and packages, which is used in TARS tars.pluginsConfig = require(helpersDirPath + '/plugins-config-processing')(); // Flags tars.flags = gutil.env; // Dev mode flag tars.isDevMode = !tars.flags.release && !tars.flags.min && !tars.flags.m; tars.useLiveReload = tars.flags.lr || tars.flags.livereload || tars.flags.tunnel; // Package name tars.packageInfo.name = tars.packageInfo.name || 'awesome_project'; /** * Log messages from TARS * @param {String} message Message to say */ tars.say = function say(message) { // Use «nice» output only for OSX if (os.platform() === 'darwin') { console.log(gutil.colors.cyan.bold('🅃 🄰 🅁 🅂 : ') + gutil.colors.white.bold(message)); } else { console.log(gutil.colors.cyan.bold('[ TARS ]: ') + gutil.colors.white.bold(message)); } }; // Generate start screen // We have to call it here, cause it has to be before all actions require(helpersDirPath + '/start-screen-generator')(gutil); // Set ulimit to 4096 for *nix FS. It needs to work with big amount of files // But you can set any value in config if (os.platform() !== 'win32') { require(helpersDirPath + '/set-ulimit')(); } /** * Log info about skipped task * @param {String} taskName Skipped task name * @param {String} reason Reason ot the skip */ tars.skipTaskLog = function skipTaskLog(taskName, reason) { gutil.log(gutil.colors.white.bold(`Skipped '${gutil.colors.cyan(taskName)}' ${reason}`)); }; /** * Beginning of a path for static files for using in css * You have to use %=static=% or __static__ placeholder in paths to static in css files * Example: background: url('%=static=%logo.png'); * Will be replaced to background: url('../img/logo.png'); * %=staticPrefixForCss=% prefix works, but it is deprecated! */ tars.config.staticPrefixForCss = `../${tars.config.fs.imagesFolderName}/`; // Fix svg config if (tars.config.hasOwnProperty('useSVG')) { tars.config.svg = { active: tars.config.useSVG, workflow: 'sprite', }; } else { const symbolsLoadingType = tars.config.svg.symbolsConfig.loadingType; if ( symbolsLoadingType !== 'inject' && symbolsLoadingType !== 'separate-file-with-link' && symbolsLoadingType !== 'separate-file' ) { tars.say( gutil.colors.yellow( `TARS does not support option ${tars.config.svg.symbolsConfig.loadingType} for symbols loading`, ), ); tars.say( gutil.colors.yellow('You can use only "inject", "separate-file" and "separate-file-with-link"'), ); tars.say(gutil.colors.yellow('"inject" will be used now!')); tars.config.svg.symbolsConfig.loadingType = 'inject'; } } if (tars.config.svg.active && tars.config.svg.workflow === 'symbols' && (tars.flags.ie || tars.flags.ie8)) { tars.say(gutil.colors.yellow('Build for IE8 is not available, then svg-symbols is used!')); } // availability check '/' if (tars.config.devPath.substr(-1) !== '/') { tars.config.devPath = tars.config.devPath + '/'; } if (tars.config.buildPath.substr(-1) !== '/') { tars.config.buildPath = tars.config.buildPath + '/'; } // Build options tars.options = { notify: true, build: { hash: tars.flags.release ? Math.random() .toString(36) .substring(7) : '', path: useBuildVersioning ? `${tars.config.buildPath}build${buildVersion}/` : tars.config.buildPath, version: useBuildVersioning ? buildVersion : '', }, watch: { isActive: false, ignored: '', persistent: true, ignoreInitial: true, }, }; // Required packages // There are only common packages tars.packages = { autoprefixer: tars.require('autoprefixer'), browserSync: tars.require('browser-sync'), cache: tars.require('gulp-cached'), changed: tars.require('gulp-changed'), chokidar: tars.require('chokidar'), concat: tars.require('gulp-concat'), data: tars.require('gulp-data'), del: tars.require('del'), gulp: require('gulp'), gulpif: tars.require('gulp-if'), gutil: gutil, importify: tars.require('gulp-importify'), notify: tars.require('gulp-notify'), plumber: tars.require('gulp-plumber'), postcss: tars.require('gulp-postcss'), rename: tars.require('gulp-rename'), replace: tars.require('gulp-replace-task'), runSequence: tars.require('gulp4-run-sequence'), sourcemaps: tars.require('gulp-sourcemaps'), streamCombiner: tars.require('stream-combiner'), through2: tars.require('through2'), }; // Links to helpers tars.helpers = { buildVersion, dateFormatter: require(helpersDirPath + '/modify-date-formatter'), tarsFsHelper: require(helpersDirPath + '/tars-fs-helper'), notifier: require(helpersDirPath + '/notifier'), watcherLog: require(helpersDirPath + '/watcher-log'), skipTaskWithEmptyPipe: require(helpersDirPath + '/skip-task-with-empty-pipe'), stringHelper: require(helpersDirPath + '/string-helper'), filterFilesByPath: require(helpersDirPath + '/filter-files-by-path'), }; /** * Info about css preprocessor * @type {String} cssPreproc.name * @type {String} cssPreproc.ext * @type {String} cssPreproc.mainExt * @type {Function} cssPreproc.ext */ switch (cssPreprocName) { case 'stylus': tars.cssPreproc = { name: 'stylus', ext: 'styl', mainExt: 'styl', preprocessor: () => tars.require('gulp-stylus')(tars.pluginsConfig['gulp-stylus']), }; break; case 'less': tars.cssPreproc = { name: 'less', ext: 'less', mainExt: 'less', preprocessor: () => tars.require('gulp-less')(tars.pluginsConfig['gulp-less']), }; break; case 'scss': default: tars.cssPreproc = { name: 'scss', ext: '{scss,sass}', mainExt: 'scss', preprocessor: () => { const sass = tars.require('gulp-sass')(tars.require('sass')); /** * FIXME: Dirty hack for fix error: * TypeError: Class constructor CommentArray cannot be invoked without 'new' * you need to find where the CommentArray comes from and get rid of it */ const { includePaths, ...options } = tars.pluginsConfig['gulp-sass']; return sass({ ...options, includePaths: [...includePaths] }) }, }; break; } /** * Info about templater * @type {String} templater.name * @type {String} templater.ext * @type {Function} templater.fn */ switch (templaterName) { case 'handlebars': tars.packages.handlebars = tars.require('gulp-compile-handlebars').Handlebars; tars.templater = { name: 'handlebars', ext: '{html,hbs}', fn: (mocksData) => tars.require('gulp-compile-handlebars')( mocksData, Object.assign({}, tars.pluginsConfig['gulp-compile-handlebars'], { helpers: require('./tasks/html/helpers/handlebars-helpers'), }), ), }; break; case 'jade': tars.templater = { name: 'jade', ext: 'jade', fn: (mocksData) => tars.require('gulp-jade')( Object.assign({}, tars.pluginsConfig['gulp-jade'], { locals: mocksData, }), ), }; break; case 'pug': default: tars.templater = { name: 'pug', ext: 'pug', fn: (mocksData) => tars.require('gulp-pug')( Object.assign({}, tars.pluginsConfig['gulp-pug'], { locals: mocksData, }), ), }; break; } ================================================ FILE: tars/tasks/css/compile-css-for-ie8.js ================================================ 'use strict'; /** * Styles compilation for IE8 */ module.exports = () => { return tars.packages.gulp.task('css:compile-css-for-ie8', done => { if (tars.flags.ie8 || tars.flags.ie) { return require(`${tars.root}/tasks/css/helpers/${tars.config.css.workflow}-compile-css-task-template`)('ie8'); } tars.skipTaskLog('css:compile-css-for-ie8', 'Stylies for IE8 are not used'); done(null); }); }; ================================================ FILE: tars/tasks/css/compile-css-for-ie9.js ================================================ 'use strict'; /** * Styles compilation for IE9 */ module.exports = () => { return tars.packages.gulp.task('css:compile-css-for-ie9', done => { if (tars.flags.ie9 || tars.flags.ie) { return require(`${tars.root}/tasks/css/helpers/${tars.config.css.workflow}-compile-css-task-template`)('ie9'); } tars.skipTaskLog('css:compile-css-for-ie9', 'Stylies for IE9 are not used'); done(null); }); }; ================================================ FILE: tars/tasks/css/compile-css.js ================================================ 'use strict'; /** * Styles compilation */ module.exports = () => { return tars.packages.gulp.task('css:compile-css', () => { return require(`${tars.root}/tasks/css/helpers/${tars.config.css.workflow}-compile-css-task-template`)(); }); }; ================================================ FILE: tars/tasks/css/compress-css.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const rename = tars.packages.rename; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; /** * Compress css-files */ module.exports = () => { return gulp.task('css:compress-css', () => { return gulp.src(`${tars.options.build.path}${tars.config.fs.staticFolderName}/css/*.css`) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while compressing css.', error); } })) .pipe(tars.require('gulp-csso')(tars.pluginsConfig['gulp-csso'])) .pipe(rename({ suffix: '.min' })) .pipe(gulp.dest(`${tars.options.build.path}${tars.config.fs.staticFolderName}/css/`)) .pipe( notifier.success('Css\'ve been minified') ); }); }; ================================================ FILE: tars/tasks/css/helpers/actions-on-sprite-task-skipping.js ================================================ const notifier = tars.helpers.notifier; const fs = require('fs'); /** * Create files with mixins, when you do not have images for sprites * @param {Object} params */ module.exports = function actionsOnSpriteTaskSkipping(params) { const blankFilePath = params.blankFilePath; const fileWithMixinsPath = params.fileWithMixinsPath; const doneCallback = params.done; const errorText = params.errorText; Promise.resolve() .then(() => { return new Promise((resolve, reject) => { fs.readFile(fileWithMixinsPath, 'utf8', (error, data) => { if (error) { return reject(error); } return resolve(data); }); }); }) .then(mixinsContent => { return new Promise((resolve, reject) => { fs.writeFile(blankFilePath, mixinsContent, error => { if (error) { return reject(error); } resolve(); }); }); }) .then(() => doneCallback(null)) .catch(error => { doneCallback(error); return notifier.error(errorText, error); }); }; ================================================ FILE: tars/tasks/css/helpers/concat-compile-css-task-template.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const gulpif = tars.packages.gulpif; const concat = tars.packages.concat; const autoprefixer = tars.packages.autoprefixer; const importify = tars.packages.importify; const postcss = tars.packages.postcss; const replace = tars.packages.replace; const sourcemaps = tars.packages.sourcemaps; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; const stringHelper = tars.helpers.stringHelper; module.exports = function generateTaskContent(browser) { browser = browser || ''; const preprocExtensions = tars.cssPreproc.ext; const preprocName = tars.cssPreproc.name; const capitalizePreprocName = stringHelper.capitalizeFirstLetter(preprocName); const stylesFolderPath = `./markup/${tars.config.fs.staticFolderName}/${preprocName}`; const sourceMapsDest = tars.config.sourcemaps.css.inline ? '' : '.'; let successMessage = `${capitalizePreprocName}-files have been compiled`; let errorMessage = 'An error occurred while compiling css'; let compiledFileName = 'main'; let generateSourceMaps = false; let postProcessors = []; let stylesFilesToConcatinate = []; let stylesFilesToIgnore = [ `${stylesFolderPath}/entry/**/*.${preprocExtensions}`, `${stylesFolderPath}/entry/**/*.css`, `./**/_*.${preprocExtensions}`, './**/_*.css', ]; let firstStylesFilesToConcatinate = [ `${stylesFolderPath}/normalize.${preprocExtensions}`, `${stylesFolderPath}/libraries/**/*.${preprocExtensions}`, `${stylesFolderPath}/libraries/**/*.css`, `${stylesFolderPath}/mixins.${preprocExtensions}`, `${stylesFolderPath}/sprites-${preprocName}/sprite_96.${preprocExtensions}`, ]; const generalStylesFilesToConcatinate = [ `${stylesFolderPath}/fonts.${preprocExtensions}`, `${stylesFolderPath}/vars.${preprocExtensions}`, `${stylesFolderPath}/GUI.${preprocExtensions}`, `${stylesFolderPath}/common.${preprocExtensions}`, `${stylesFolderPath}/plugins/**/*.${preprocExtensions}`, `${stylesFolderPath}/plugins/**/*.css`, `./markup/${tars.config.fs.componentsFolderName}/**/*.${preprocExtensions}`, `./markup/${tars.config.fs.componentsFolderName}/**/*.css`, ]; const lastStylesFilesToConcatinate = [ `${stylesFolderPath}/etc/**/*.${preprocExtensions}`, `${stylesFolderPath}/etc/**/*.css`, ]; if (tars.config.postcss && tars.config.postcss.length) { tars.config.postcss.forEach((postProcessor) => { postProcessors.push(require(postProcessor.name)(postProcessor.options)); }); } if (preprocName === 'less' || preprocName === 'stylus') { firstStylesFilesToConcatinate.push( `${stylesFolderPath}/sprites-${preprocName}/sprite-png.${preprocExtensions}`, ); } switch (browser) { case 'ie8': stylesFilesToConcatinate.push( firstStylesFilesToConcatinate, `${stylesFolderPath}/sprites-${preprocName}/svg-fallback-sprite.${preprocExtensions}`, `${stylesFolderPath}/sprites-${preprocName}/sprite-ie.${preprocExtensions}`, generalStylesFilesToConcatinate, `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie8.${preprocExtensions}`, `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie8.css`, lastStylesFilesToConcatinate, ); stylesFilesToIgnore.push( `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie9.${preprocExtensions}`, `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie9.css`, ); postProcessors.push(autoprefixer({ browsers: ['ie 8'] })); generateSourceMaps = false; compiledFileName += `_${browser}`; successMessage = `${capitalizePreprocName}-files for IE8 have been compiled`; errorMessage = 'An error occurred while compiling css for IE8.'; break; case 'ie9': stylesFilesToConcatinate.push(firstStylesFilesToConcatinate); if (tars.config.svg.active && tars.config.svg.workflow === 'sprite') { stylesFilesToConcatinate.push( `${stylesFolderPath}/sprites-${preprocName}/svg-sprite.${preprocExtensions}`, ); } stylesFilesToConcatinate.push( generalStylesFilesToConcatinate, `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie9.${preprocExtensions}`, `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie9.css`, lastStylesFilesToConcatinate, ); stylesFilesToIgnore.push( `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie8.${preprocExtensions}`, `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie8.css`, ); postProcessors.push(autoprefixer({ browsers: ['ie 9'] })); compiledFileName += `_${browser}`; generateSourceMaps = false; successMessage = `${capitalizePreprocName}-files for IE9 have been compiled`; errorMessage = 'An error occurred while compiling css for IE9.'; break; // Styles for all browsers except IE8, IE9 default: stylesFilesToConcatinate.push(firstStylesFilesToConcatinate); if (tars.config.svg.active && tars.config.svg.workflow === 'sprite') { stylesFilesToConcatinate.push( `${stylesFolderPath}/sprites-${preprocName}/svg-sprite.${preprocExtensions}`, ); } stylesFilesToIgnore.push( `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie9.${preprocExtensions}`, `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie9.css`, `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie8.${preprocExtensions}`, `./markup/${tars.config.fs.componentsFolderName}/**/ie/ie8.css`, ); stylesFilesToConcatinate.push(generalStylesFilesToConcatinate, lastStylesFilesToConcatinate); postProcessors.push(autoprefixer()); generateSourceMaps = tars.config.sourcemaps.css.active && tars.options.watch.isActive; break; } stylesFilesToConcatinate = [].concat.apply([], stylesFilesToConcatinate); return gulp .src(stylesFilesToConcatinate, { base: process.cwd(), ignore: stylesFilesToIgnore }) .pipe(gulpif(generateSourceMaps, sourcemaps.init())) .pipe( plumber({ errorHandler(error) { notifier.error(errorMessage, error); this.emit('end'); }, }), ) .pipe( importify(compiledFileName + '.' + tars.cssPreproc.mainExt, { cssPreproc: preprocName, }), ) .pipe(tars.cssPreproc.preprocessor()) .pipe( replace({ patterns: [ { match: /%=staticPrefixForCss=%|%=static=%|__static__/gim, replacement: tars.config.staticPrefixForCss, }, ], usePrefix: false, }), ) .pipe(postcss(postProcessors)) .pipe(concat(`${compiledFileName}${tars.options.build.hash}.css`)) .pipe(gulpif(generateSourceMaps, sourcemaps.write(sourceMapsDest))) .pipe(gulp.dest(`${tars.config.devPath}${tars.config.fs.staticFolderName}/css/`)) .pipe(browserSync.reload({ stream: true, match: '**/*.css' })) .pipe(notifier.success(successMessage)); }; ================================================ FILE: tars/tasks/css/helpers/manual-compile-css-task-template.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const gulpif = tars.packages.gulpif; const rename = tars.packages.rename; const autoprefixer = tars.packages.autoprefixer; const postcss = tars.packages.postcss; const replace = tars.packages.replace; const sourcemaps = tars.packages.sourcemaps; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; const stringHelper = tars.helpers.stringHelper; module.exports = function generateTaskContent(browser) { browser = browser || ''; const preprocExtensions = tars.cssPreproc.ext; const preprocName = tars.cssPreproc.name; const capitalizePreprocName = stringHelper.capitalizeFirstLetter(preprocName); const stylesFolderPath = `./markup/${tars.config.fs.staticFolderName}/${preprocName}`; const sourceMapsDest = tars.config.sourcemaps.css.inline ? '' : '.'; let successMessage = `${capitalizePreprocName}-files have been compiled`; let errorMessage = 'An error occurred while compiling css'; let generateSourceMaps = false; let postProcessors = []; let stylesFilesToCompile = []; let stylesFilesToIgnore = [`./**/_*.${preprocExtensions}`, './**/_*.css']; if (tars.config.postcss && tars.config.postcss.length) { tars.config.postcss.forEach((postProcessor) => { postProcessors.push(require(postProcessor.name)(postProcessor.options)); }); } switch (browser) { case 'ie8': stylesFilesToCompile.push(`${stylesFolderPath}/entry/ie/*_ie8.${preprocExtensions}`); postProcessors.push(autoprefixer({ browsers: ['ie 8'] })); generateSourceMaps = false; successMessage = `${capitalizePreprocName}-files for IE8 have been compiled`; errorMessage = 'An error occurred while compiling css for IE8.'; break; case 'ie9': stylesFilesToCompile.push(`${stylesFolderPath}/entry/ie/*_ie9.${preprocExtensions}`); postProcessors.push(autoprefixer({ browsers: ['ie 9'] })); generateSourceMaps = false; successMessage = `${capitalizePreprocName}-files for IE9 have been compiled`; errorMessage = 'An error occurred while compiling css for IE9.'; break; // Styles for all browsers except IE8, IE9 default: stylesFilesToCompile.push(`${stylesFolderPath}/entry/*.${preprocExtensions}`); postProcessors.push(autoprefixer()); generateSourceMaps = tars.config.sourcemaps.css.active && tars.options.watch.isActive; break; } return gulp .src(stylesFilesToCompile, { ignore: stylesFilesToIgnore, }) .pipe(gulpif(generateSourceMaps, sourcemaps.init())) .pipe( plumber({ errorHandler(error) { notifier.error(errorMessage, error); this.emit('end'); }, }), ) .pipe(tars.cssPreproc.preprocessor()) .pipe( replace({ patterns: [ { match: /%=staticPrefixForCss=%|%=static=%|__static__/gim, replacement: tars.config.staticPrefixForCss, }, ], usePrefix: false, }), ) .pipe(postcss(postProcessors)) .pipe(rename({ suffix: tars.options.build.hash })) .pipe(gulpif(generateSourceMaps, sourcemaps.write(sourceMapsDest))) .pipe(gulp.dest(`${tars.config.devPath}${tars.config.fs.staticFolderName}/css/`)) .pipe(browserSync.reload({ stream: true, match: '**/*.css' })) .pipe(notifier.success(successMessage)); }; ================================================ FILE: tars/tasks/css/helpers/sprite-mixins/less-raster-sprite-mixins.less ================================================ .sprite-position(@sprite) { @sprite-offset-x: ~`"@{sprite}".split(', ')[2]`; @sprite-offset-y: ~`"@{sprite}".split(', ')[3]`; background-position: @sprite-offset-x @sprite-offset-y; } .sprite-image(@sprite) { @sprite-image: ~`'%=static=%png-sprite/96dpi/' + "@{sprite}".split(', ')[8].replace(']', '').replace(/\'/g, '')`; background-image: url(@sprite-image); } .sprite-mixin-template(@sprite) { .sprite-image(@sprite); .sprite-position(@sprite); width: ~`"@{sprite}".split(', ')[4]`; height: ~`"@{sprite}".split(', ')[5]`; } .bg-template(@sprite, @repeat: no-repeat) { .sprite-mixin-template(@sprite); @sprite-total-width: ~`"@{sprite}".split(', ')[6]`; @sprite-total-height: ~`"@{sprite}".split(', ')[7]`; background-size: @sprite-total-width, @sprite-total-height; background-repeat: @repeat; } .highDpiMedia(@sprite) {} ================================================ FILE: tars/tasks/css/helpers/sprite-mixins/less-svg-fallback-sprite-mixins.less ================================================ .svg-sprite-position(@svg-sprite) { @svg-sprite-offset-x: ~`"@{svg-sprite}".split(', ')[2]`; @svg-sprite-offset-y: ~`"@{svg-sprite}".split(', ')[3]`; background-position: @svg-sprite-offset-x @svg-sprite-offset-y; } .svg-sprite-image(@svg-sprite) { @svg-sprite-image-url: ~`'../img/rastered-svg-sprite/' + "@{svg-sprite}".split(', ')[8].replace(']', '').replace(/\'/g, '')`; background-image: url(@svg-sprite-image-url); } .bg-svg(@svg-sprite, @repeat: no-repeat) { .svg-sprite-image(@svg-sprite); .svg-sprite-position(@svg-sprite); width: ~`"@{svg-sprite}".split(', ')[4]`; height: ~`"@{svg-sprite}".split(', ')[5]`; background-repeat: @repeat; } ================================================ FILE: tars/tasks/css/helpers/sprite-mixins/less-svg-sprite-mixins.less ================================================ .svg-sprite-position(@svg-sprite) { @svg-sprite-offset-x: ~`"@{svg-sprite}".split(', ')[0].replace('[', '')`; @svg-sprite-offset-y: ~`"@{svg-sprite}".split(', ')[1]`; background-position: @svg-sprite-offset-x @svg-sprite-offset-y; } .bg-svg(@svg-sprite, @repeat: no-repeat) { background-image: url('%=static=%svg-sprite/{{imgName}}'); .svg-sprite-position(@svg-sprite); width: ~`"@{svg-sprite}".split(', ')[2]`; height: ~`"@{svg-sprite}".split(', ')[3]`; background-repeat: @repeat; } ================================================ FILE: tars/tasks/css/helpers/sprite-mixins/scss-raster-sprite-mixins.scss ================================================ @mixin sprite-position($sprite) { $sprite-offset-x: nth($sprite, 3); $sprite-offset-y: nth($sprite, 4); background-position: $sprite-offset-x $sprite-offset-y; } @mixin sprite-image($sprite) { $sprite-image: nth($sprite, 9); background-image: url(%=static=%png-sprite/96dpi/#{$sprite-image}); } @mixin sprite-mixin-template($sprite) { @include sprite-image($sprite); @include sprite-position($sprite); width: nth($sprite, 5); height: nth($sprite, 6); } @mixin bg($sprite, $repeat: no-repeat) { @include sprite-mixin-template($sprite); $sprite-total-width: nth($sprite, 7); $sprite-total-height: nth($sprite, 8); background-size: $sprite-total-width, $sprite-total-height; background-repeat: $repeat; } ================================================ FILE: tars/tasks/css/helpers/sprite-mixins/scss-svg-fallback-sprite-mixins.scss ================================================ @mixin svg-sprite-position($svg-sprite) { $svg-sprite-offset-x: nth($svg-sprite, 3); $svg-sprite-offset-y: nth($svg-sprite, 4); background-position: $svg-sprite-offset-x $svg-sprite-offset-y; } @mixin svg-sprite-image($svg-sprite) { $svg-sprite-image: nth($svg-sprite, 9); background-image: url(%=static=%rastered-svg-sprite/#{$svg-sprite-image}); } @mixin bg-svg($svg-sprite, $repeat: no-repeat) { @include svg-sprite-image($svg-sprite); @include svg-sprite-position($svg-sprite); width: nth($svg-sprite, 5); height: nth($svg-sprite, 6); background-repeat: $repeat; } ================================================ FILE: tars/tasks/css/helpers/sprite-mixins/scss-svg-sprite-mixins.scss ================================================ @mixin svg-sprite-position($svg-sprite) { $svg-sprite-offset-x: nth($svg-sprite, 1); $svg-sprite-offset-y: nth($svg-sprite, 2); background-position: $svg-sprite-offset-x $svg-sprite-offset-y; } @mixin bg-svg($svg-sprite, $repeat: no-repeat) { background-image: url('%=static=%svg-sprite/{{imgName}}'); @include svg-sprite-position($svg-sprite); width: nth($svg-sprite, 3); height: nth($svg-sprite, 4); background-repeat: $repeat; } ================================================ FILE: tars/tasks/css/helpers/sprite-mixins/stylus-raster-sprite-mixins.styl ================================================ bg-template($sprite, $repeat = no-repeat) { width: $sprite[4]; height: $sprite[5]; background-position: $sprite[2] $sprite[3]; background-image: url('%=static=%png-sprite/96dpi/' + $sprite[8]); background-size: $sprite[6] $sprite[7]; background-repeat: $repeat; } highDpiMedia($sprite) {} ================================================ FILE: tars/tasks/css/helpers/sprite-mixins/stylus-svg-fallback-sprite-mixins.styl ================================================ svg-sprite-position($svg-sprite) { $svg-sprite-offset-x = $svg-sprite[2]; $svg-sprite-offset-y = $svg-sprite[3]; background-position: $svg-sprite-offset-x $svg-sprite-offset-y; } svg-sprite-image($svg-sprite) { background-image: url('%=static=%rastered-svg-sprite/' + $svg-sprite[8]); } bg-svg($svg-sprite, $repeat = no-repeat) { svg-sprite-image($svg-sprite); svg-sprite-position($svg-sprite); width: $svg-sprite[4]; height: $svg-sprite[5]; background-repeat: $repeat; } ================================================ FILE: tars/tasks/css/helpers/sprite-mixins/stylus-svg-sprite-mixins.styl ================================================ svg-sprite-position($svg-sprite) { $svg-sprite-offset-x = $svg-sprite[0]; $svg-sprite-offset-y = $svg-sprite[1]; background-position: $svg-sprite-offset-x $svg-sprite-offset-y; } bg-svg($svg-sprite, $repeat = no-repeat) { background-image: url('%=static=%svg-sprite/{{imgName}}'); svg-sprite-position($svg-sprite); width: $svg-sprite[2]; height: $svg-sprite[3]; background-repeat: $repeat; } ================================================ FILE: tars/tasks/css/make-fallback-for-svg.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const skipTaskWithEmptyPipe = tars.helpers.skipTaskWithEmptyPipe; const stringHelper = tars.helpers.stringHelper; const staticFolderName = tars.config.fs.staticFolderName; const imagesFolderName = tars.config.fs.imagesFolderName; const preprocExtension = tars.cssPreproc.mainExt; const preprocName = tars.cssPreproc.name; const actionsOnSpriteTaskSkipping = require(`${tars.root}/tasks/css/helpers/actions-on-sprite-task-skipping`); /** * Make sprite for svg-fallback and styles for this sprite * Return pipe with styles for sprite */ module.exports = () => { return gulp.task('css:make-fallback-for-svg', (done) => { const errorText = 'An error occurred while making fallback for svg.'; function actionsOnTaskSkipping() { return actionsOnSpriteTaskSkipping({ blankFilePath: `./markup/${staticFolderName}/${preprocName}/sprites-${preprocName}/svg-fallback-sprite.${preprocExtension}`, fileWithMixinsPath: `${tars.root}/tasks/css/helpers/sprite-mixins/${preprocName}-svg-fallback-sprite-mixins.${preprocExtension}`, errorText, done, }); } if ( tars.config.svg.active && tars.config.svg.workflow === 'sprite' && (tars.flags.ie8 || tars.flags.ie) ) { const cssTemplatePath = `./markup/${staticFolderName}/${preprocName}/sprite-generator-templates`; const spriteData = gulp .src( `${tars.config.devPath}${staticFolderName}/${imagesFolderName}/rastered-svg-images/*.png`, ) .pipe( plumber({ errorHandler(error) { notifier.error(errorText, error); }, }), ) .pipe(skipTaskWithEmptyPipe('css:make-fallback-for-svg', actionsOnTaskSkipping)) .pipe( tars.require('gulp.spritesmith')( Object.assign( {}, { imgName: `svg-fallback-sprite${tars.options.build.hash}.png`, cssName: `svg-fallback-sprite.${preprocExtension}`, algorithm: 'binary-tree', algorithmOpts: { sort: false, }, padding: 4, cssTemplate: `${cssTemplatePath}/${preprocName}.svg-fallback-sprite.mustache`, }, tars.pluginsConfig['gulp.spritesmith']['svg-fallback'], ), ), ); spriteData.img .pipe( gulp.dest( `${tars.config.devPath}${staticFolderName}/${imagesFolderName}/rastered-svg-sprite/`, ), ) .pipe(notifier.success('Sprite-img for svg is ready!')); spriteData.css .pipe(gulp.dest(`./markup/${staticFolderName}/${preprocName}/sprites-${preprocName}/`)) .pipe( notifier.success( `${stringHelper.capitalizeFirstLetter(preprocName)} for svg-sprite is ready`, ), ); return spriteData; } tars.skipTaskLog('css:make-fallback-for-svg', 'Svg-fallback is not used'); actionsOnTaskSkipping(); }); }; ================================================ FILE: tars/tasks/css/make-sprite-for-svg.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const skipTaskWithEmptyPipe = tars.helpers.skipTaskWithEmptyPipe; const stringHelper = tars.helpers.stringHelper; const preprocName = tars.cssPreproc.name; const preprocExtension = tars.cssPreproc.mainExt; const staticFolderName = tars.config.fs.staticFolderName; const imagesFolderPath = `${tars.config.devPath}${staticFolderName}/${tars.config.fs.imagesFolderName}`; const preprocFoldePath = `./markup/${staticFolderName}/${preprocName}`; const actionsOnSpriteTaskSkipping = require(`${tars.root}/tasks/css/helpers/actions-on-sprite-task-skipping`); /** * Make sprite for svg and styles for this sprite * Return pipe with styles for sprite */ module.exports = () => { return gulp.task('css:make-sprite-for-svg', (done) => { const errorText = 'An error occurred while making sprite for svg.'; function actionsOnTaskSkipping() { return actionsOnSpriteTaskSkipping({ blankFilePath: `${preprocFoldePath}/sprites-${preprocName}/svg-sprite.${preprocExtension}`, fileWithMixinsPath: `${tars.root}/tasks/css/helpers/sprite-mixins/${preprocName}-svg-sprite-mixins.${preprocExtension}`, errorText, done, }); } if (tars.config.svg.active && tars.config.svg.workflow === 'sprite') { return gulp .src(`${imagesFolderPath}/minified-svg/*.svg`) .pipe( plumber({ errorHandler(error) { notifier.error(errorText, error); }, }), ) .pipe(skipTaskWithEmptyPipe('css:make-sprite-for-svg', actionsOnTaskSkipping)) .pipe( tars.require('gulp-svg-spritesheet')( Object.assign( {}, { cssPathSvg: '', templateSrc: `${preprocFoldePath}/sprite-generator-templates/${preprocName}.svg-sprite.mustache`, templateDest: `${preprocFoldePath}/sprites-${preprocName}/svg-sprite.${preprocExtension}`, imgName: `sprite${tars.options.build.hash}.svg`, }, tars.pluginsConfig['gulp-svg-spritesheet'], ), ), ) .pipe(gulp.dest(`${imagesFolderPath}/svg-sprite/sprite${tars.options.build.hash}.svg`)) .pipe( notifier.success( `${stringHelper.capitalizeFirstLetter(preprocName)} for svg-sprite is ready.`, ), ); } tars.skipTaskLog('css:make-sprite-for-svg', 'SVG is not used or you prefer symbols workflow'); actionsOnTaskSkipping(); }); }; ================================================ FILE: tars/tasks/css/make-sprite.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const stringHelper = tars.helpers.stringHelper; const staticFolderName = tars.config.fs.staticFolderName; const imagesFolderName = tars.config.fs.imagesFolderName; const usedDpiArray = tars.config.useImagesForDisplayWithDpi; const preprocExtension = tars.cssPreproc.mainExt; const preprocName = tars.cssPreproc.name; const skipTaskWithEmptyPipe = tars.helpers.skipTaskWithEmptyPipe; const actionsOnSpriteTaskSkipping = require(`${tars.root}/tasks/css/helpers/actions-on-sprite-task-skipping`); /** * Make sprite and styles for this sprite */ module.exports = () => { return gulp.task('css:make-sprite', (done) => { const dpiLength = usedDpiArray.length; const cssTemplatePath = `./markup/${staticFolderName}/${preprocName}/sprite-generator-templates`; const spritesmithConfig = tars.pluginsConfig['gulp.spritesmith']['regular-raster-sprite']; const errorText = 'An error occurred while making png-sprite.'; let spriteData = []; let dpiConfig = {}; usedDpiArray.forEach((dpiValue) => { dpiConfig[`dpi${dpiValue}`] = true; }); function actionsOnTaskSkipping() { return actionsOnSpriteTaskSkipping({ blankFilePath: `./markup/${staticFolderName}/${preprocName}/sprites-${preprocName}/sprite_96.${preprocExtension}`, fileWithMixinsPath: `${tars.root}/tasks/css/helpers/sprite-mixins/${preprocName}-raster-sprite-mixins.${preprocExtension}`, done, errorText, }); } /* eslint-disable no-loop-func */ for (let i = 0; i < dpiLength; i++) { spriteData.push( gulp .src( `./markup/${staticFolderName}/${imagesFolderName}/sprite/${usedDpiArray[i]}dpi/*.png`, ) .pipe( plumber({ errorHandler(error) { notifier.error(errorText, error); }, }), ) .pipe( tars.require('gulp.spritesmith')( Object.assign( {}, { imgName: `sprite${tars.options.build.hash}.png`, cssName: `sprite_${usedDpiArray[i]}.${preprocExtension}`, algorithm: 'binary-tree', algorithmOpts: { sort: false, }, cssOpts: dpiConfig, padding: (i + 1) * 4, cssTemplate: `${cssTemplatePath}/${preprocName}.sprite.mustache`, }, spritesmithConfig, { padding: (i + 1) * spritesmithConfig.padding, }, ), ), ), ); spriteData[i].img .pipe( gulp.dest( `${tars.config.devPath}${staticFolderName}/${imagesFolderName}/png-sprite/${usedDpiArray[i]}dpi/`, ), ) .pipe(notifier.success(`Sprite img with dpi = ${usedDpiArray[i]} is ready`)); } /* eslint-enable no-loop-func */ // Returns css for dpi 96 return spriteData[0].css .pipe(skipTaskWithEmptyPipe('css:make-sprite', actionsOnTaskSkipping)) .pipe(gulp.dest(`./markup/${staticFolderName}/${preprocName}/sprites-${preprocName}/`)) .pipe( notifier.success(stringHelper.capitalizeFirstLetter(preprocName) + ' for sprites is ready'), ); }); }; ================================================ FILE: tars/tasks/css/move-separate.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const cache = tars.packages.cache; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const staticFolderName = tars.config.fs.staticFolderName; /** * Copy separate Css-files to dev directory */ module.exports = () => { return gulp.task('css:move-separate', () => { return gulp.src(`./markup/${staticFolderName}/${tars.cssPreproc.name}/separate-css/**/*.css`) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while moving separate css-files.', error); } })) .pipe(cache('separate-css')) .pipe(gulp.dest(`${tars.config.devPath}${staticFolderName}/css/separate-css`)) .pipe( notifier.success('Separate css files\'s been copied') ); }); }; ================================================ FILE: tars/tasks/html/compile-templates.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const replace = tars.packages.replace; const plumber = tars.packages.plumber; const rename = tars.packages.rename; const through2 = tars.packages.through2; const fs = require('fs'); const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; const generateStaticPath = require(`${tars.root}/tasks/html/helpers/generate-static-path`); const templaterName = require(`${tars.root}/helpers/get-templater-name`)(tars.config.templater.toLowerCase()); const templaterIsPugOrJade = templaterName === 'jade' || templaterName === 'pug'; let patterns = []; /** * Traverse recursively through data-object * If any property is a funciton, * this function will be called * @param {Object} obj Current object to traverse in current step * @param {Object} fullData Object with all data */ function traverseThroughObject(obj, fullData) { for (let property in obj) { if (obj.hasOwnProperty(property)) { if (typeof obj[property] === 'object') { traverseThroughObject(obj[property], fullData); } if (typeof obj[property] === 'function') { obj[property] = obj[property].call(null, fullData); } } } } /** * Concat all data for all components to one file * @return {Object} Object with data for components */ function concatComponentsData() { let dataEntry; let readyMocksData; try { dataEntry = fs.readFileSync(`${tars.config.devPath}temp/mocksData.js`, 'utf8'); } catch (er) { dataEntry = false; } if (dataEntry) { eval(`readyMocksData = {${dataEntry}}`); // readyMocksData passed as second argument // to be an argument for each function from data traverseThroughObject(readyMocksData, readyMocksData); } else { readyMocksData = '{}'; } // Add helpers for Jade and Pug into readyMocksData in case of using Jade as templater if (templaterIsPugOrJade) { readyMocksData = Object.assign(readyMocksData, { [`${templaterName}Helpers`]: require(`${tars.root}/tasks/html/helpers/${templaterName}-helpers`) }); } return readyMocksData; } if (!tars.flags.ie8 && !tars.flags.ie) { patterns.push( { match: /|/gm, replacement: '' } ); } if (!tars.flags.ie9 && !tars.flags.ie) { patterns.push( { match: //gm, replacement: '' } ); } patterns.push( { match: '%=min=%', replacement: tars.flags.min || tars.flags.release || tars.flags.m ? '.min' : '' }, { match: '%=hash=%', replacement: tars.flags.release ? tars.options.build.hash : '' } ); if ( tars.config.svg.active && tars.config.svg.workflow === 'symbols' && tars.config.svg.symbolsConfig.loadingType === 'inject' ) { patterns.push( { match: '%=symbols=%', replacement: (() => { /* eslint-disable no-unused-vars */ try { return fs.readFileSync(`${tars.config.devPath}temp/svg-symbols${tars.options.build.hash}.svg`, 'utf8'); } catch (error) { return ''; } /* eslint-enable no-unused-vars */ }) } ); } else { patterns.push( { match: '%=symbols=%', replacement: '' } ); } if ( !tars.config.svg.active || tars.config.svg.workflow !== 'symbols' || tars.config.svg.symbolsConfig.loadingType !== 'separate-file-with-link' || !tars.config.svg.symbolsConfig.usePolyfillForExternalSymbols ) { patterns.push( { match: '', replacement: '' }, { match: '', replacement: '' } ); } /** * Add some specific functions for Jade/Pug-processing * @return {Pipe} */ function jadeAndPugInheritanceProcessing() { const inheritanceOptions = { basedir: './markup/', extension: `.${templaterName}`, skip: ['node_modules'] }; const isInheritanceEnabled = tars.options.watch.isActive && templaterIsPugOrJade; if (isInheritanceEnabled) { return tars.packages.streamCombiner( tars.packages.cache('templates'), tars.require(`gulp-${templaterName}-inheritance`)(inheritanceOptions), tars.helpers.filterFilesByPath([ new RegExp(`\/markup\/${tars.config.fs.componentsFolderName}\/`), /^_[\w]+.(jade|pug)/ ]) ); } return tars.packages.gutil.noop(); } /** * HTML compilation of pages templates. * Templates with _ prefix won't be compiled */ module.exports = () => { return gulp.task('html:compile-templates', () => { let mocksData; let error; let compileError; let filesToCompile = [ `./markup/pages/**/*.${tars.templater.ext}`, `!./markup/pages/**/_*.${tars.templater.ext}` ]; if (templaterIsPugOrJade && tars.options.watch.isActive) { filesToCompile.push( `!./markup/${tars.config.fs.componentsFolderName}/**/_*.${tars.templater.ext}`, `./markup/${tars.config.fs.componentsFolderName}/**/*.${tars.templater.ext}` ); } try { mocksData = concatComponentsData(); } catch (er) { error = er; mocksData = false; } return gulp.src(filesToCompile) .pipe(plumber({ errorHandler(pipeError) { notifier.error('An error occurred while compiling to html.', pipeError); this.emit('end'); compileError = true; } })) .pipe(jadeAndPugInheritanceProcessing()) .pipe( mocksData ? tars.templater.fn(mocksData) : through2.obj( function () { /* eslint-disable no-invalid-this */ this.emit('error', new Error('An error occurred with data-files!\n' + error)); /* eslint-enable no-invalid-this */ } ) ) .pipe(replace({ patterns: patterns, usePrefix: false })) .pipe(generateStaticPath()) .pipe(rename(pathToFileToRename => { if (templaterIsPugOrJade) { pathToFileToRename.dirname = pathToFileToRename.dirname.replace(/^pages/, ''); } pathToFileToRename.extname = '.html'; })) .pipe(gulp.dest(`${tars.config.devPath}`)) .on('end', () => { if (!compileError) { browserSync.reload(); notifier.success('Templates\'ve been compiled', { notStream: true }); } }); }); }; ================================================ FILE: tars/tasks/html/concat-mocks-data.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const plumber = tars.packages.plumber; const concat = tars.packages.concat; const notifier = tars.helpers.notifier; const pagesAndDataFilesProcessing = require(`${tars.root}/tasks/html/helpers/pages-and-data-files-processing`); /** * concat data for components and some other sources to one file */ module.exports = () => { return gulp.task('html:concat-mocks-data', () => { return gulp .src( [ `./markup/pages/**/*.${tars.templater.ext}`, `!./markup/pages/**/_*.${tars.templater.ext}`, `./markup/${tars.config.fs.componentsFolderName}/**/data/data.js`, `${tars.config.devPath}temp/symbols-data-template.js`, ], { allowEmpty: true }, ) .pipe( plumber({ errorHandler(error) { notifier.error( `An error occurred while concating ${tars.config.fs.componentsFolderName}'s data.`, error, ); }, }), ) .pipe(pagesAndDataFilesProcessing()) .pipe(concat('mocksData.js', { newLine: ',\n\n' })) .pipe(gulp.dest(`${tars.config.devPath}temp/`)) .pipe(notifier.success(`Data for ${tars.config.fs.componentsFolderName} ready`)); }); }; ================================================ FILE: tars/tasks/html/helpers/generate-static-path.js ================================================ 'use strict'; const through2 = tars.packages.through2; const path = require('path'); const Buffer = require('buffer').Buffer; /** * Generate static path for pages */ module.exports = function generateStaticPath() { function getStaticPrefix(pageDepth) { const staticPrefix = tars.config.fs.staticFolderName; if (tars.useLiveReload) { return `/${staticPrefix}/`; } if (tars.config.generateStaticPath) { return `${pageDepth.join('')}${staticPrefix}/`; } } return through2.obj(function (file, enc, callback) { // Get all directories array for current page from page directory const directoriesArray = path.parse(file.relative).dir.split(path.sep); // Generate static path as '../' as many times, as directories array length + tars.config.staticPrefix const pageDepth = directoriesArray.map(value => { if (value) { return '../'; } }); let newPageContent = file.contents.toString(); newPageContent = newPageContent.replace( /%=staticPrefix=%|%=static=%|__static__/g, getStaticPrefix(pageDepth) ); if (tars.config.svg.active && tars.config.svg.workflow === 'symbols' && tars.config.svg.symbolsConfig.loadingType === 'separate-file-with-link') { newPageContent = newPageContent.replace( /xlink:href="(.*)"/gim, (str, $1) => `xlink:href="${pageDepth.join('') + $1}"` ); } file.contents = Buffer.from(newPageContent); this.push(file); // eslint-disable-line no-invalid-this return callback(); }, callback => callback()); }; ================================================ FILE: tars/tasks/html/helpers/handlebars-helpers.js ================================================ 'use strict'; const Handlebars = tars.packages.handlebars; const Dates = require('./utils/dates'); const Utils = require('./utils/utils'); const builtInHandlebarsHelpers = { /** * Repeat helper * @param {Number} n number of iterations * @param {[type]} options [description] * @return {[type]} [description] */ repeat(n, options) { options = options || {}; const count = n - 1; let content = ''; for (let index = 0; index <= count; index++) { options.data.index = index; content += options.fn(this, { data: options.data }); } return new Handlebars.SafeString(content); }, /** * If helper with params * @param {[type]} a [description] * @param {[type]} b [description] * @param {String} options operation * @return {[type]} [description] */ is(leftOperand, operation, rightOperand, options) { const a = leftOperand || false; const b = rightOperand || false; if (operation && typeof operation === 'string') { switch (operation) { // Not strictly equal case '==': if (a == b) { return options.fn(this); } else { return options.inverse(this); } break; // Strictly equal case '===': if (a === b) { return options.fn(this); } else { return options.inverse(this); } break; // a > b checking case '>': if (a > b) { return options.fn(this); } else { return options.inverse(this); } break; // a >= b checking case '>=': if (a >= b) { return options.fn(this); } else { return options.inverse(this); } break; // a < b checking case '<': if (a < b) { return options.fn(this); } else { return options.inverse(this); } break; // a <= b checking case '<=': if (a <= b) { return options.fn(this); } else { return options.inverse(this); } break; // a != b checking case '!=': if (a != b) { return options.fn(this); } else { return options.inverse(this); } break; // a !== b checking case '!==': if (a !== b) { return options.fn(this); } else { return options.inverse(this); } break; // Action, if operation is unknown default: throw new Error( 'Operation is unknown!\n"is" helper supports only:\n' + '"==",\n' + '"===",\n' + '">",\n' + '">=",\n' + '"<",\n' + '"<=",\n' + '"!=",\n' + '"!==",\n' ); } } else { throw new Error('Operation has to be received to "is" helper and has to be a string'); } }, /** * Str to lower case * @param {String} str [description] * @return {[type]} [description] */ toLowerCase(str) { str = Utils.castToString(str); return str.toLowerCase(); }, /** * Str to upper case * @param {String} str [description] * @return {[type]} [description] */ toUpperCase(str) { str = Utils.castToString(str); return str.toUpperCase(); }, /** * Capitalize first symbol of str * @param {String} str [description] * @return {[type]} [description] */ capitalizeFirst(str) { str = Utils.castToString(str); return str.charAt(0).toUpperCase() + str.slice(1); }, /** * Remove whitespaces from received data to helper * @param {[type]} options [description] * @return {[type]} [description] */ strip(options) { options = options || {}; let _data = {}; if (options._data) { _data = Handlebars.createFrame(options._data); } const content = options.fn(this, {data: _data}).replace(/>(\s+)<'); return new Handlebars.SafeString(content); }, /** * Create template for symbol including * @param {Object} options Params for template * @param {String} options.iconName The name of used icon * @param {String} options.className Classname for svg element * @param {String} options.iconWidth Width for svg element * @param {String} options.iconHeight Height for svg element * @return {String} Compiled Handlebars template */ Icon(options) { const iconName = options.hash.iconName; let pathToSymbolsSprite = ''; if (!iconName) { throw new Error('iconName has to be received to "icon" helper and has to be a string'); } const iconData = options.data.root.__iconsData[iconName]; const symbolsConfig = tars.config.svg.symbolsConfig; const symbolsSpriteFileName = `svg-symbols${tars.options.build.hash}.svg`; if (!iconData) { throw new Error('There is no icon with name: ' + iconName); } if (symbolsConfig.loadingType === 'separate-file-with-link') { pathToSymbolsSprite = symbolsConfig.pathToExternalSymbolsFile + symbolsSpriteFileName; } pathToSymbolsSprite += '#' + iconName; const className = options.hash.className || 'icon__' + iconName; const iconWidth = options.hash.iconWidth || iconData.width; const iconHeight = options.hash.iconHeight || iconData.height; const content = ` `; return new Handlebars.SafeString(content); }, /** * {{formatDate}} * Port of formatDate-js library (http://bit.ly/18eo2xw) * @param {[type]} date [description] * @param {[type]} format [description] * @return {[type]} [description] */ formatDate(date, format) { return Dates.format(new Date(date), format); }, /** * {{now}} * @param {[type]} format [description] * @return {[type]} [description] */ now(format) { const date = new Date(); if (Utils.isUndefined(format)) { return date; } else { return Dates.format(date, format); } }, /** * {{i18n}} * @author: Laurent Goderre * @param {String} context * @param {Object} options * @return {String} * @example: (See the "button-i18n" example) */ i18n(context, options) { let language = void 0; if (typeof context !== 'string') { throw 'Key must be of type \'string\''; } language = (typeof options.hash.language === 'string' ? options.hash.language : this.language); if (typeof language === 'undefined') { throw 'The \'language\' parameter is not defined'; } if (typeof this[language] === "undefined") { throw 'No strings found for language \'" + language + "\''; } if (typeof this[language][context] === "undefined") { throw 'No string for key \'" + context + "\' for language \'" + language + "\''; } return this[language][context]; } }; module.exports = Object.assign( builtInHandlebarsHelpers, require(tars.root + '/user-tasks/html/helpers/handlebars-helpers') ); ================================================ FILE: tars/tasks/html/helpers/jade-helpers.js ================================================ 'use strict'; const builtInPugHelpers = { /** * Icon helper for Jade * It returns template for svg-symbols including * @param {Object} options * @param {String} options.iconName Name of the used icon * @param {String} options.className Classname for svg element * @param {String} options.iconWidth Width for svg element * @param {String} options.iconHeight Height for svg element * @return {String} Ready template for svg-symbols including */ Icon(options) { const iconName = options.iconName; let pathToSymbolsSprite = ''; if (!iconName) { throw new Error('iconName has to be received to "icon" mixin and has to be a string'); } const iconData = this.__iconsData[iconName]; const symbolsConfig = tars.config.svg.symbolsConfig; const symbolsSpriteFileName = `svg-symbols${tars.options.build.hash}.svg`; if (!iconData) { throw new Error('There is no icon with name: ' + iconName); } if (symbolsConfig.loadingType === 'separate-file-with-link') { pathToSymbolsSprite = symbolsConfig.pathToExternalSymbolsFile + symbolsSpriteFileName; } pathToSymbolsSprite += `#${iconName}`; const className = options.className || `icon__${iconName}`; const iconWidth = options.iconWidth || iconData.width; const iconHeight = options.iconHeight || iconData.height; return ` `; } }; let userHelpers; try { userHelpers = require(`${tars.root}/user-tasks/html/helpers/jade-helpers`); } catch (error) { userHelpers = {}; } module.exports = Object.assign( builtInPugHelpers, userHelpers ); ================================================ FILE: tars/tasks/html/helpers/pages-and-data-files-processing.js ================================================ 'use strict'; const through2 = tars.packages.through2; const File = tars.packages.gutil.File; const path = require('path'); const Buffer = require('buffer').Buffer; const tarsEnvValue = process.env.TARS_ENV; /** * Strip 'const data = {' and '};' from data-file content or just remove last ; * @param {String} content Content of data-file to processing * @return {String} Processed data-file content */ function dataFileProcessing(content) { return content .replace(/^[\w\s-]+?=\s*?{\s*([\S\s]*)\s*}\s*?;?$/m, '$1') .replace(/^'([\w\s-]+)'/, '$1') .replace(/;$/m, ''); } module.exports = function pagesAndDataFilesProcessing() { let hrefArray = []; let pageNameArray = []; return through2.obj(function (file, enc, callback) { const parsedFileRelativePath = path.parse(file.relative); const fileName = parsedFileRelativePath.base; const pathParts = parsedFileRelativePath.dir.split(path.sep); let fileContent = file.contents.toString(); let namePrefix = ''; if (pathParts.length > 2) { namePrefix = pathParts.slice(0, -2).join('_') + '_'; } switch (fileName) { case 'data.js': // Create new component name for ready data-file fileContent = namePrefix + dataFileProcessing(fileContent); // Add '' to ready component name if (fileContent.search(/^([\w\s-]+)/) === 0) { fileContent = fileContent.replace(/^([\w\s-]+)/, '\'$1\''); } if (fileContent.replace(/\s/g, '').length) { file.contents = Buffer.from(fileContent); this.push(file); // eslint-disable-line no-invalid-this } break; case 'symbols-data-template.js': this.push(file); // eslint-disable-line no-invalid-this break; default: if (parsedFileRelativePath.dir) { parsedFileRelativePath.dir += '/'; } hrefArray.push(`${parsedFileRelativePath.dir}${parsedFileRelativePath.name}.html`); pageNameArray.push(parsedFileRelativePath.dir + parsedFileRelativePath.name); break; } return callback(); }, function (callback) { let pagesListFileContent = '__pages: ['; hrefArray.forEach((value, index) => { if (index) { pagesListFileContent += ','; } pagesListFileContent += `{ name: '${pageNameArray[index]}', href: '${value}' }`; }); pagesListFileContent += ']'; const pagesListFile = new File({ base: './pages/', cwd: __dirname, path: './pages/all', contents: Buffer.from(pagesListFileContent) }); this.push(pagesListFile); // eslint-disable-line no-invalid-this if (tarsEnvValue) { this.push(new File({ // eslint-disable-line no-invalid-this path: '.', contents: Buffer.from(`TARS_ENV: '${tarsEnvValue}'`) })); } return callback(); }); }; ================================================ FILE: tars/tasks/html/helpers/pug-helpers.js ================================================ 'use strict'; const builtInPugHelpers = { /** * Icon helper for Jade * It returns template for svg-symbols including * @param {Object} options * @param {String} options.iconName Name of the used icon * @param {String} options.className Classname for svg element * @param {String} options.iconWidth Width for svg element * @param {String} options.iconHeight Height for svg element * @return {String} Ready template for svg-symbols including */ Icon(options) { const iconName = options.iconName; let pathToSymbolsSprite = ''; if (!iconName) { throw new Error('iconName has to be received to "icon" mixin and has to be a string'); } if (!this.__iconsData) { throw new Error('please, ensure that "symbols" is set in tars.config.svg.workflow'); } const iconData = this.__iconsData[iconName]; const symbolsConfig = tars.config.svg.symbolsConfig; const symbolsSpriteFileName = `svg-symbols${tars.options.build.hash}.svg`; if (!iconData) { throw new Error('There is no icon with name: ' + iconName); } if (symbolsConfig.loadingType === 'separate-file-with-link') { pathToSymbolsSprite = symbolsConfig.pathToExternalSymbolsFile + symbolsSpriteFileName; } pathToSymbolsSprite += `#${iconName}`; const className = options.className || `icon__${iconName}`; const iconWidth = options.iconWidth || iconData.width; const iconHeight = options.iconHeight || iconData.height; return ` `; } }; let userHelpers; try { userHelpers = require(`${tars.root}/user-tasks/html/helpers/pug-helpers`); } catch (error) { userHelpers = {}; } module.exports = Object.assign( builtInPugHelpers, userHelpers ); ================================================ FILE: tars/tasks/html/helpers/utils/dates.js ================================================ /** * Handlebars Helpers Utils * http://github.com/assemble/handlebars-helpers * Copyright (c) 2013 Jon Schlinkert, Brian Woodward, contributors * Licensed under the MIT License (MIT). */ 'use strict'; var Dates = module.exports = {}; Dates.padNumber = function(num, count, padCharacter) { if (typeof padCharacter === 'undefined') { padCharacter = '0'; } var lenDiff = count - String(num).length; var padding = ''; if (lenDiff > 0) { while (lenDiff--) { padding += padCharacter; } } return padding + num; }; Dates.dayOfYear = function(date) { var oneJan = new Date(date.getFullYear(), 0, 1); return Math.ceil((date - oneJan) / 86400000); }; Dates.weekOfYear = function(date) { var oneJan = new Date(date.getFullYear(), 0, 1); return Math.ceil((((date - oneJan) / 86400000) + oneJan.getDay() + 1) / 7); }; Dates.isoWeekOfYear = function(date) { var target = new Date(date.valueOf()); var dayNr = (date.getDay() + 6) % 7; target.setDate(target.getDate() - dayNr + 3); var jan4 = new Date(target.getFullYear(), 0, 4); var dayDiff = (target - jan4) / 86400000; return 1 + Math.ceil(dayDiff / 7); }; Dates.tweleveHour = function(date) { if (date.getHours() > 12) { return date.getHours() - 12; } return date.getHours(); }; Dates.timeZoneOffset = function(date) { var hoursDiff = -date.getTimezoneOffset() / 60; var result = Dates.padNumber(Math.abs(hoursDiff), 4); return (hoursDiff > 0 ? '+' : '-') + result; }; Dates.format = function(date, format) { var match = null; return format.replace(Dates.formats, function(m, p) { switch (p) { case 'a': return Dates.abbreviatedWeekdays[date.getDay()]; case 'A': return Dates.fullWeekdays[date.getDay()]; case 'b': return Dates.abbreviatedMonths[date.getMonth()]; case 'B': return Dates.fullMonths[date.getMonth()]; case 'c': return date.toLocaleString(); case 'C': return Math.round(date.getFullYear() / 100); case 'd': return Dates.padNumber(date.getDate(), 2); case 'D': return Dates.format(date, '%m/%d/%y'); case 'e': return Dates.padNumber(date.getDate(), 2, ' '); case 'F': return Dates.format(date, '%Y-%m-%d'); case 'h': return Dates.format(date, '%b'); case 'H': return Dates.padNumber(date.getHours(), 2); case 'I': return Dates.padNumber(Dates.tweleveHour(date), 2); case 'j': return Dates.padNumber(Dates.dayOfYear(date), 3); case 'k': return Dates.padNumber(date.getHours(), 2, ' '); case 'l': return Dates.padNumber(Dates.tweleveHour(date), 2, ' '); case 'L': return Dates.padNumber(date.getMilliseconds(), 3); case 'm': return Dates.padNumber(date.getMonth() + 1, 2); case 'M': return Dates.padNumber(date.getMinutes(), 2); case 'n': return '\n'; case 'p': if (date.getHours() > 11) { return 'PM'; } else { return 'AM'; } break; case 'P': return Dates.format(date, '%p').toLowerCase(); case 'r': return Dates.format(date, '%I:%M:%S %p'); case 'R': return Dates.format(date, '%H:%M'); case 's': return date.getTime() / 1000; case 'S': return Dates.padNumber(date.getSeconds(), 2); case 't': return '\t'; case 'T': return Dates.format(date, '%H:%M:%S'); case 'u': if (date.getDay() === 0) { return 7; } else { return date.getDay(); } break; case 'U': return Dates.padNumber(Dates.weekOfYear(date), 2); case 'v': return Dates.format(date, '%e-%b-%Y'); case 'V': return Dates.padNumber(Dates.isoWeekOfYear(date), 2); case 'W': return Dates.padNumber(Dates.weekOfYear(date), 2); case 'w': return Dates.padNumber(date.getDay(), 2); case 'x': return date.toLocaleDateString(); case 'X': return date.toLocaleTimeString(); case 'y': return String(date.getFullYear()).substring(2); case 'Y': return date.getFullYear(); case 'z': return Dates.timeZoneOffset(date); default: return match; } }); }; Dates.formats = /%(a|A|b|B|c|C|d|D|e|F|h|H|I|j|k|l|L|m|M|n|p|P|r|R|s|S|t|T|u|U|v|V|W|w|x|X|y|Y|z)/g; Dates.abbreviatedWeekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat']; Dates.fullWeekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; Dates.abbreviatedMonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; Dates.fullMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; ================================================ FILE: tars/tasks/html/helpers/utils/utils.js ================================================ /** * Handlebars Helpers: Utils * http://github.com/assemble/handlebars-helpers * Copyright (c) 2013, 2014 Jon Schlinkert, Brian Woodward, contributors * Licensed under the MIT License (MIT). */ 'use strict'; module.exports = { isUndefined(value) { return typeof value === 'undefined' || value.toString() === '[object Function]' || (value.hash != null); }, castToString(value) { if (typeof value !== 'string') { value.toString(); } return value; } }; ================================================ FILE: tars/tasks/html/modify-html.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const gulpif = tars.packages.gulpif; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; /** * Minify HTML (optional task) */ module.exports = () => { return gulp.task('html:modify-html', () => { const usersModifyOptions = require(tars.root + '/user-tasks/html/helpers/modify-options'); const minifyOpts = Object.assign( tars.pluginsConfig['gulp-htmlmin'], usersModifyOptions.minifyOpts ); /* eslint-disable camelcase */ const prettifyOpts = Object.assign( tars.pluginsConfig['gulp-html-prettify'], usersModifyOptions.prettifyOpts ); /* eslint-enable camelcase */ return gulp.src(`${tars.config.devPath}**/*.html`) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while processing compiled html-files.', error); } })) .pipe(gulpif( tars.config.minifyHtml, tars.require('gulp-htmlmin')(minifyOpts), tars.require('gulp-html-prettify')(prettifyOpts) )) .pipe(gulp.dest(`${tars.config.devPath}`)) .pipe( notifier.success('Compiled html\'ve been processed.') ); }); }; ================================================ FILE: tars/tasks/images/helpers/symbols-data-template.js ================================================ __iconsData: { <% _.forEach(icons, icon => { %> '<%= icon.name %>': { width: '<%= icon.width %>px', height: '<%= icon.height %>px' }, <% }); %> } ================================================ FILE: tars/tasks/images/make-symbols-sprite.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const gulpif = tars.packages.gulpif; const rename = tars.packages.rename; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const skipTaskWithEmptyPipe = tars.helpers.skipTaskWithEmptyPipe; const svgImagesPath = `${tars.config.devPath}${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}/minified-svg/`; let readySymbolSpritePath = `${tars.config.devPath}${tars.config.svg.symbolsConfig.pathToExternalSymbolsFile}`; if (tars.config.svg.symbolsConfig.loadingType === 'inject') { readySymbolSpritePath = `${tars.config.devPath}temp/`; } /** * Create svg-symbols sprite */ module.exports = () => { return gulp.task('images:make-symbols-sprite', (done) => { if (tars.config.svg.active && tars.config.svg.workflow === 'symbols') { return gulp .src(`${svgImagesPath}**/*.svg`) .pipe( plumber({ errorHandler(error) { notifier.error('An error occurred while creating symbols sprite.', error); }, }), ) .pipe(skipTaskWithEmptyPipe('images:make-symbols-sprite', done)) .pipe( tars.require('gulp-svg-symbols')({ templates: [ `${tars.root}/tasks/images/helpers/svg-symbols.svg`, `${tars.root}/tasks/images/helpers/symbols-data-template.js`, ], transformData: (svg, defaultData) => { return { id: defaultData.id, width: svg.width, height: svg.height, name: svg.name, }; }, }), ) .pipe( gulpif( /[.]svg$/, rename((spritePath) => { spritePath.basename += tars.options.build.hash; }), ), ) .pipe(gulpif(/[.]svg$/, gulp.dest(readySymbolSpritePath))) .pipe(gulpif(/[.]js$/, gulp.dest(`${tars.config.devPath}temp/`))) .pipe(notifier.success("Symbols sprite's been created")); } tars.skipTaskLog('images:make-symbols-sprite', 'SVG is not used or you prefer svg-sprite workflow'); done(null); }); }; ================================================ FILE: tars/tasks/images/minify-images.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const changed = tars.packages.changed; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const imagesFolderPath = `${tars.config.devPath}${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}`; /** * Minify png and jpg images */ module.exports = () => { const imagemin = tars.require('gulp-imagemin'); return gulp.task('images:minify-images', () => { return gulp.src( /* eslint-disable indent */ [ `${imagesFolderPath}/**/*.{png,jpg,svg}`, `!${imagesFolderPath}/minified-svg/*.svg`, `!${imagesFolderPath}/**/svg-symbols${tars.options.build.hash}.svg` ], /* eslint-enable indent */ { base: process.cwd() + '/' } ) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while minifying all images.', error); } })) .pipe(changed(imagesFolderPath)) .pipe( imagemin([ imagemin.jpegtran({ progressive: true }), imagemin.optipng({ optimizationLevel: 5 }), imagemin.svgo({ plugins: [ { cleanupIDs: false }, { removeViewBox: false }, { convertPathData: false }, { mergePaths: false }, ], }) ], { verbose: true }) ) .pipe(gulp.dest('./')) .pipe( notifier.success('Rastered images\'ve been minified') ); }); }; ================================================ FILE: tars/tasks/images/minify-svg.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const changed = tars.packages.changed; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const svgImagesPath = `${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}`; /** * Minify svg-images (optional task) */ module.exports = () => { const imagemin = tars.require('gulp-imagemin'); return gulp.task('images:minify-svg', (done) => { if (tars.config.svg.active) { return gulp .src(`./markup/${svgImagesPath}/svg/*.svg`) .pipe( plumber({ errorHandler(error) { notifier.error('An error occurred while minifying svg.', error); }, }) ) .pipe( changed(`${tars.config.devPath}${svgImagesPath}/minified-svg`, { hasChanged: changed.compareLastModifiedTime, extension: '.svg', }) ) .pipe( imagemin([ imagemin.svgo({ plugins: [ { cleanupIDs: false }, { removeViewBox: false }, { convertPathData: false }, { mergePaths: false }, ], }) ]) ) .pipe(gulp.dest(`${tars.config.devPath}${svgImagesPath}/minified-svg/`)) .pipe(notifier.success('SVG\'ve been minified')); } tars.skipTaskLog('images:minify-svg', 'SVG is not used'); done(null); }); }; ================================================ FILE: tars/tasks/images/move-content-img.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const cache = tars.packages.cache; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; const contentImagesFolder = `${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}/content`; /** * Move images for content */ module.exports = () => { return gulp.task('images:move-content-img', () => { return gulp.src( /* eslint-disable indent */ [ `./markup/${contentImagesFolder}/**/*.*`, `!./markup/${contentImagesFolder}/**/*.tmp` ] /* eslint-enable indent */ ) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while moving content images.', error); } })) .pipe(cache('move-content-img')) .pipe(gulp.dest(`${tars.config.devPath}${contentImagesFolder}`)) .pipe(browserSync.reload({ stream: true })) .pipe( notifier.success('Content images\'ve been moved') ); }); }; ================================================ FILE: tars/tasks/images/move-general-img.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const cache = tars.packages.cache; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; const generalImagesFolder = `${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}/general`; /** * Move general images */ module.exports = () => { return gulp.task('images:move-general-img', () => { return gulp.src( /* eslint-disable indent */ [ `./markup/${generalImagesFolder}/**/*.*`, `!./markup/${generalImagesFolder}/**/*.tmp` ] /* eslint-enable indent */ ) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while moving general images.', error); } })) .pipe(cache('move-general-img')) .pipe(gulp.dest(`${tars.config.devPath}${generalImagesFolder}`)) .pipe(browserSync.reload({ stream: true })) .pipe( notifier.success('General images\'ve been moved') ); }); }; ================================================ FILE: tars/tasks/images/move-plugins-img.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const cache = tars.packages.cache; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; const pluginsImagesFolder = `${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}/plugins`; /** * Move images for plugins */ module.exports = () => { return gulp.task('images:move-plugins-img', () => { return gulp.src( /* eslint-disable indent */ [ `./markup/${pluginsImagesFolder}/**/*.*`, `!./markup/${pluginsImagesFolder}/**/*.tmp` ] /* eslint-enable indent */ ) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while moving plugin\'s imgs.', error); } })) .pipe(cache('move-plugins-img')) .pipe(gulp.dest(`${tars.config.devPath}${pluginsImagesFolder}`)) .pipe(browserSync.reload({ stream: true })) .pipe( notifier.success('Plugins\' images\'ve been moved') ); }); }; ================================================ FILE: tars/tasks/images/raster-svg.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const cache = tars.packages.cache; const changed = tars.packages.changed; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const imagesPath = `${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}`; /** * Raster SVG-files (optional task) */ module.exports = () => { return gulp.task('images:raster-svg', done => { if (tars.config.svg.active && tars.config.svg.workflow === 'sprite' && (tars.flags.ie8 || tars.flags.ie)) { return gulp.src(`./markup/${imagesPath}/svg/*.svg`) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while rastering svg.', error); } })) .pipe(cache('raster-svg')) .pipe( changed( `${imagesPath}/rastered-svg-images`, { hasChanged: changed.compareLastModifiedTime, extension: '.png' } ) ) .pipe(tars.require('gulp-svg2png')()) .pipe(gulp.dest(`${tars.config.devPath}${imagesPath}/rastered-svg-images`)) .pipe( notifier.success('SVG\'ve been rastered') ); } tars.skipTaskLog('images:raster-svg', 'Rastering SVG is not used'); done(null); }); }; ================================================ FILE: tars/tasks/js/check.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const cache = tars.packages.cache; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const jsPathesToLint = [].concat.apply([], [ `./markup/${tars.config.fs.componentsFolderName}/**/*.js`, `!./markup/${tars.config.fs.componentsFolderName}/**/_*.js`, `!./markup/${tars.config.fs.componentsFolderName}/**/data/data.js`, tars.config.js.lintJsCodeBeforeModules ? tars.config.js.jsPathsToConcatBeforeModulesJs : [], tars.config.js.lintJsCodeAfterModules ? tars.config.js.jsPathsToConcatAfterModulesJs : [] ]); /** * Check JS for style and errors (optional task) */ module.exports = () => { return gulp.task('js:check', done => { /* eslint-disable no-case-declarations */ if (tars.config.js.lint) { switch (tars.config.js.workflow) { case 'modular': switch (tars.config.js.bundler) { case 'webpack': default: tars.skipTaskLog('js:check', 'Code will be linted by built-in linter in bundler'); return done(null); } case 'concat': default: const eslint = tars.require('gulp-eslint'); return gulp.src(jsPathesToLint) .pipe(plumber({ errorHandler() { notifier.error('An error occurred while checking js.'); } })) .pipe(cache('eslint')) .pipe(eslint()) .pipe(eslint.formatEach()) .pipe(eslint.failAfterError()); } } /* eslint-enable no-case-declarations */ tars.skipTaskLog('js:check', 'JavaScript check is not used'); done(null); }); }; ================================================ FILE: tars/tasks/js/concat-processing.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const concat = tars.packages.concat; const streamCombiner = tars.packages.streamCombiner; const plumber = tars.packages.plumber; const gulpif = tars.packages.gulpif; const rename = tars.packages.rename; const sourcemaps = tars.packages.sourcemaps; const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; const cwd = process.cwd(); let generateSourceMaps = false; const staticFolderName = tars.config.fs.staticFolderName; const destFolder = `${tars.config.devPath}${staticFolderName}/js`; const compressJs = tars.flags.release || tars.flags.min || tars.flags.m; const sourceMapsDest = tars.config.sourcemaps.js.inline ? '' : '.'; const jsPaths = [].concat.apply( [], [ `./markup/${staticFolderName}/js/framework/**/*.js`, `./markup/${staticFolderName}/js/libraries/**/*.js`, `./markup/${staticFolderName}/js/plugins/**/*.js`, tars.config.js.jsPathsToConcatBeforeModulesJs, `./markup/${tars.config.fs.componentsFolderName}/**/*.js`, tars.config.js.jsPathsToConcatAfterModulesJs, ], ); /** * Stream of base processing with JavaScript. * ------------------------------------------ * There are: * - concat js files; * - add hash like a suffix of filename; * - write header in the start of main file; * - write footer in the end of main file; * - write source map; * - write main file at fs. */ function base() { return streamCombiner( gulpif(tars.config.js.useBabel, tars.require('gulp-babel')()), concat({ cwd: cwd, path: 'main.js' }), rename({ suffix: tars.options.build.hash }), gulp.dest(destFolder), ); } /** * Stream of minimized with JavaScript. * ------------------------------------ * There are: * - removing `console.log()` and `debug`; * - uglified code; * - add '.min' suffix for main file; * - write source maps; * - write main file at fs. */ function compress() { if (compressJs) { return streamCombiner( tars.require('gulp-terser')(tars.pluginsConfig['gulp-terser']), rename({ suffix: '.min' }), gulp.dest(destFolder), ); } return tars.packages.gutil.noop(); } module.exports = () => { /** * Task for processing with JavaScript files. * ------------------------------------------ * There are: * - call lint task; * - prevent pipe breaking; * - creation of stream; * - init source maps; * - base processing; * - compress code; * - notify about end of task; * - reloading browser's page. */ return gulp.task('js:concat-processing', () => { generateSourceMaps = tars.config.sourcemaps.js.active && tars.options.watch.isActive; return gulp .src(jsPaths, { base: cwd, ignore: [ `./markup/${tars.config.fs.componentsFolderName}/**/data/data.js`, './markup/**/_*.js', `./markup/${staticFolderName}/js/separate-js/**/*.js`, ], }) .pipe( plumber({ errorHandler(error) { notifier.error('An error occurred while processing js-files.', error); }, }), ) .pipe(gulpif(generateSourceMaps, sourcemaps.init())) .pipe(base()) .pipe(compress()) .pipe(gulpif(generateSourceMaps, sourcemaps.write(sourceMapsDest))) .pipe(notifier.success('JavaScript has been processed')) .pipe(browserSync.reload({ stream: true })); }); }; ================================================ FILE: tars/tasks/js/helpers/separate-files-filter.js ================================================ 'use strict'; const through2 = tars.packages.through2; const path = require('path'); /** * Filter files for move-separate js */ module.exports = function separateFilesFilter() { return through2.obj(function (file, enc, callback) { const fileName = path.basename(file.relative); switch (fileName) { case 'html5shiv-3.7.2.min.js': if (tars.flags.ie || tars.flags.ie8) { this.push(file); // eslint-disable-line no-invalid-this } break; case 'svg4everybody.min.js': if ( tars.config.svg.active && tars.config.svg.workflow === 'symbols' && tars.config.svg.symbolsConfig.loadingType === 'separate-file-with-link' && tars.config.svg.symbolsConfig.usePolyfillForExternalSymbols ) { this.push(file); // eslint-disable-line no-invalid-this } break; default: this.push(file); // eslint-disable-line no-invalid-this break; } return callback(); }, callback => callback()); }; ================================================ FILE: tars/tasks/js/move-separate.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const cache = tars.packages.cache; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const separateFilesFilter = require(`${tars.root}/tasks/js/helpers/separate-files-filter`); const separateJsFilesPath = `${tars.config.fs.staticFolderName}/js/separate-js`; /** * Copy separate Js-files to dev directory */ module.exports = () => { return gulp.task('js:move-separate', () => { return gulp.src(`./markup/${separateJsFilesPath}/**/*.js`) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while moving separate js-files.', error); } })) .pipe(separateFilesFilter()) .pipe(cache('separate-js')) .pipe(gulp.dest(`${tars.config.devPath}${separateJsFilesPath}`)) .pipe( notifier.success('Separate js files\'s been copied') ); }); }; ================================================ FILE: tars/tasks/js/processing.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); module.exports = () => { return gulp.task( 'js:processing', gulp.series('js:check', (done) => { switch (tars.config.js.workflow) { case 'modular': // It is not necessary to start webpack with HMR with live reload // cause Browser-sync has middleware with webpack. if (tars.config.js.webpack.useHMR && tars.useLiveReload) { done(); } else { runSequence(`js:${tars.config.js.bundler}-processing`, done); } break; case 'concat': default: runSequence('js:concat-processing', done); break; } }), ); }; ================================================ FILE: tars/tasks/js/webpack-processing.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const gutil = tars.packages.gutil; const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; const cwd = process.cwd(); module.exports = () => { return gulp.task('js:webpack-processing', done => { tars.require('webpack')(require(`${cwd}/webpack.config`), (error, stats) => { if (!error) { error = stats.toJson().errors[0]; } if (error) { notifier.error('JavaScript has not been processed', error); } else { console.log(stats.toString({ colors: true })); notifier.success('JavaScript has been processed', { notStream: true }); if (tars.useLiveReload) { browserSync.reload(); } } // Task never errs in watch mode, it waits and recompiles if (!tars.options.watch.isActive && error) { done( new gutil.PluginError( 'webpack-processing', new Error('An error occured during webpack build process') ) ); } else { if (!done.called) { done.called = true; done(); } } }); }); }; ================================================ FILE: tars/tasks/main/build-dev.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); /** * Build dev-version (without watchers) */ module.exports = () => { return gulp.task('main:build-dev', function(cb) { tars.options.notify = false; runSequence( 'service:clean', ['images:minify-svg', 'images:raster-svg'], [ 'css:make-sprite-for-svg', 'css:make-fallback-for-svg', 'css:make-sprite', 'images:make-symbols-sprite', ], [ 'css:compile-css', 'css:compile-css-for-ie8', 'css:compile-css-for-ie9', 'css:move-separate', 'html:concat-mocks-data', 'other:move-misc-files', 'other:move-fonts', 'other:move-assets', 'images:move-content-img', 'images:move-plugins-img', 'images:move-general-img', 'js:move-separate', ], ['js:processing', 'html:compile-templates'], cb, ); }); }; ================================================ FILE: tars/tasks/main/build.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const gutil = tars.packages.gutil; const runSequence = tars.packages.runSequence.use(gulp); /** * Build release version */ module.exports = () => { return gulp.task( 'main:build', gulp.series('main:build-dev', (done) => { runSequence( ['html:modify-html', 'images:minify-images'], 'main:create-build', ['css:compress-css'], 'service:zip-build', () => { console.log( gutil.colors.black.bold( '\n------------------------------------------------------------', ), ); tars.say(gutil.colors.green.bold(' Build has been created successfully!')); if (tars.config.useBuildVersioning) { tars.say(gutil.colors.white.bold('Build version is: ', tars.options.build.version)); } console.log( gutil.colors.black.bold( '------------------------------------------------------------\n', ), ); done(); }, ); }), ); }; ================================================ FILE: tars/tasks/main/create-build.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; /** * Copy files from dev to build directory. Create build directory with new build version */ module.exports = () => { return gulp.task('main:create-build', () => { return gulp.src([`${tars.config.devPath}**/*.*`, `!${tars.config.devPath}temp/**`], { base: `${tars.config.devPath}` }) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while running create-build task.', error); } })) .pipe(gulp.dest(tars.options.build.path)) .pipe( notifier.success('Pre-build task is finished') ); }); }; ================================================ FILE: tars/tasks/main/dev.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const notify = tars.packages.notify; const browserSync = tars.packages.browserSync; const path = require('path'); const env = process.env; const cwd = process.cwd(); function setWatchMode(cb) { tars.options.notify = true; tars.options.watch.isActive = true; cb(); } /** * Build dev-version with watchers and livereload. */ module.exports = () => { /** * Start watchers and show notify */ function devTaskFinallyActions(done) { // require system and user's watchers tars.helpers.tarsFsHelper.getWatchers().forEach((file) => require(file)()); if (tars.config.notifyConfig.useNotify && env.NODE_ENV !== 'production' && !env.DISABLE_NOTIFIER) { notify({ title: tars.config.notifyConfig.title, icon: path.resolve(tars.root + '/icons/tars.png'), }).write('Build has been created!'); } else { tars.say('Build has been created!'); } done(); } return gulp.task( 'main:dev', gulp.series(setWatchMode, 'main:build-dev', (done) => { if (tars.useLiveReload) { const useHMR = tars.config.js.workflow === 'modular' && tars.config.js.bundler === 'webpack' && tars.config.js.webpack.useHMR; let browserSyncConfig = tars.pluginsConfig.browserSync; /* eslint-disable no-undefined */ browserSyncConfig = Object.assign(browserSyncConfig, { middleware: browserSyncConfig.middleware || [], port: env.BROWSERSYNC_PORT || browserSyncConfig.port, logConnections: browserSyncConfig.logConnections || true, logLevel: browserSyncConfig.logLevel || 'info', reloadOnRestart: browserSyncConfig.reloadOnRestart || true, tunnel: tars.flags.tunnel, }); /* eslint-enable no-undefined */ if (!useHMR) { browserSync.init(browserSyncConfig); devTaskFinallyActions(done); } else { const webpackConfig = require(`${cwd}/webpack.config`); const webpackInstance = tars.require('webpack')(webpackConfig); const webpackDevMiddlewareInstance = tars.require('webpack-dev-middleware')( webpackInstance, { publicPath: `/${tars.config.fs.staticFolderName}/js/`, stats: { colors: true, }, }, ); const browserSyncMiddleware = [ webpackDevMiddlewareInstance, tars.require('webpack-hot-middleware')(webpackInstance), ]; browserSyncConfig.middleware = browserSyncConfig.middleware.concat(browserSyncMiddleware); tars.say('Wait for a moment, please. Webpack is preparing bundle for you...'); webpackDevMiddlewareInstance.waitUntilValid(() => { browserSync.init(browserSyncConfig); devTaskFinallyActions(done); }); } } else { // Do not start Browser-sync without livereload, just watchers and notifications devTaskFinallyActions(done); } }), ); }; ================================================ FILE: tars/tasks/other/move-assets.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const gulpif = tars.packages.gulpif; const cache = tars.packages.cache; const rename = tars.packages.rename; const path = require('path'); const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; const imgAssets = `${tars.config.devPath}${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}/assets/`; const otherAssets = `${tars.config.devPath}${tars.config.fs.staticFolderName}/${tars.config.fs.componentsFolderName}-assets/`; /** * Move files from components' assets to ready build */ module.exports = () => { return gulp.task('other:move-assets', () => { return gulp.src(`./markup/${tars.config.fs.componentsFolderName}/**/assets/**/*.*`) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while moving assets.', error); } })) .pipe(cache('move-assets')) .pipe(rename(filepath => { let splittedPath = filepath.dirname.split(path.sep); splittedPath.pop(); filepath.dirname = splittedPath.join(path.sep); })) .pipe( gulpif( /\.(svg|png|jpg|jpeg|jpe|gif|tiff|bmp|webp)$/i, gulp.dest(imgAssets), gulp.dest(otherAssets) ) ) .pipe(browserSync.reload({ stream: true })) .pipe(notifier.success('Assets\'ve been moved')); }); }; ================================================ FILE: tars/tasks/other/move-fonts.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const cache = tars.packages.cache; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; const fontsFolderPath = `${tars.config.fs.staticFolderName}/fonts`; /** * Move fonts-files to dev directory */ module.exports = () => { return gulp.task('other:move-fonts', () => { return gulp.src(`./markup/${fontsFolderPath}/**/*.*`) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while moving fonts.', error); } })) .pipe(cache('move-fonts')) .pipe(gulp.dest(`${tars.config.devPath}${fontsFolderPath}`)) .pipe(browserSync.reload({ stream: true })) .pipe( notifier.success('Fonts\'ve been moved') ); }); }; ================================================ FILE: tars/tasks/other/move-misc-files.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const browserSync = tars.packages.browserSync; /** * Move misc files */ module.exports = () => { return gulp.task('other:move-misc-files', () => { return gulp.src(`./markup/${tars.config.fs.staticFolderName}/misc/**/*`, { dot: true }) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while moving misc-files.', error); } })) .pipe(gulp.dest(`${tars.config.devPath}`)) .pipe(browserSync.reload({ stream: true })) .pipe( notifier.success('Misc files\'ve been moved') ); }); }; ================================================ FILE: tars/tasks/services/clean.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const del = tars.packages.del; const preProcName = tars.cssPreproc.name; const preprocExtension = tars.cssPreproc.mainExt; const spritesCssPath = `./markup/${tars.config.fs.staticFolderName}/${preProcName}/sprites-${preProcName}`; let pathsToDel = [ `${tars.config.devPath}`, `${spritesCssPath}/sprite_96.${preprocExtension}`, `${spritesCssPath}/svg-fallback-sprite.${preprocExtension}`, `${spritesCssPath}/svg-sprite.${preprocExtension}`, './.tmpTemplater/', './.tmpPreproc/' ]; /** * Clean dev directory and cache */ module.exports = () => { return gulp.task('service:clean', done => { if (!tars.config.useBuildVersioning && !tars.options.watch.isActive) { pathsToDel.push(tars.options.build.path); } del(pathsToDel, {force: true}).then(() => { done(); }); }); }; ================================================ FILE: tars/tasks/services/create-fs.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const del = tars.packages.del; const fs = require('fs'); const staticFolderName = tars.config.fs.staticFolderName; const staticFolderPath = `markup/${staticFolderName}`; const componentsFolderName = tars.config.fs.componentsFolderName; const componentsFolderPath = `markup/${componentsFolderName}`; const imagesFolderPath = `${staticFolderPath}/${tars.config.fs.imagesFolderName}`; let paths = [ `${staticFolderPath}/js/framework`, `${staticFolderPath}/js/libraries`, `${staticFolderPath}/js/plugins`, imagesFolderPath, `${imagesFolderPath}/content`, `${imagesFolderPath}/general`, `${imagesFolderPath}/plugins`, `${imagesFolderPath}/sprite` ]; tars.config.useImagesForDisplayWithDpi.forEach(dpiValue => { paths.push(`${imagesFolderPath}/sprite/${dpiValue}dpi`); }); paths.push( `${imagesFolderPath}/svg`, `${staticFolderPath}/fonts`, `${staticFolderPath}/${tars.config.cssPreprocessor}`, `${componentsFolderPath}/_template/assets`, `${componentsFolderPath}/_template/ie` ); /** * Create fs for project */ module.exports = () => { return gulp.task('service:create-fs', done => { const mkdirp = tars.require('mkdirp'); if (staticFolderName !== 'static') { fs.renameSync('./markup/static/', `./markup/${staticFolderName}`); } if (componentsFolderName !== 'components') { del.sync('./markup/components/'); } paths.forEach(path => { mkdirp(path, error => { if (error) { console.error(error); } }); }); done(null); }); }; ================================================ FILE: tars/tasks/services/init.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const gutil = tars.packages.gutil; const del = tars.packages.del; /** * Init builder, apply css-preprocessor and templater */ module.exports = () => { return gulp.task( 'service:init', gulp.series('service:create-fs', (done) => { const ncp = tars.require('ncp'); const TEMPLATES_PATH = './templates'; const PAGES_PATH = 'markup/pages'; const COMPONENTS_PATH = `markup/${tars.config.fs.componentsFolderName}`; /** * Apply templates files * @type {String} type of template, templater or preprocessor * @return {Object} Promise */ function applyTemplates(type) { return new Promise((resolveTemplatesApplying, rejectTemplatesApplying) => { if ( (type === 'templater' && tars.flags['exclude-html']) || (type === 'preprocessor' && tars.flags['exclude-css']) ) { return resolveTemplatesApplying(); } if (type === 'templater') { const templaterPartsPath = `${TEMPLATES_PATH}/${tars.templater.name}`; Promise.all([ new Promise((resolve, reject) => { ncp(`${templaterPartsPath}/${PAGES_PATH}`, `./${PAGES_PATH}`, (error) => { if (error) { return reject(error); } return resolve(); }); }), new Promise((resolve, reject) => { ncp( `${templaterPartsPath}/markup/components`, `./${COMPONENTS_PATH}`, (error) => { if (error) { return reject(error); } return resolve(); }, ); }), ]) .then(() => resolveTemplatesApplying()) .catch((error) => rejectTemplatesApplying(error)); } else { const preprocPartsPath = `${TEMPLATES_PATH}/${tars.cssPreproc.name}/markup`; Promise.all([ new Promise((resolve, reject) => { ncp( `${preprocPartsPath}/static`, `./markup/${tars.config.fs.staticFolderName}`, (error) => { if (error) { return reject(error); } return resolve(); }, ); }), new Promise((resolve, reject) => { ncp(`${preprocPartsPath}/components`, `./${COMPONENTS_PATH}`, (error) => { if (error) { return reject(error); } return resolve(); }); }), ]) .then(() => resolveTemplatesApplying()) .catch((error) => rejectTemplatesApplying(error)); } }); } /** * Generate start screen * @return {Object} Promise */ function generateStartScreen() { return new Promise((resolve) => { if (tars.cli) { tars.say("It's almost ready!"); } else { console.log('\n'); tars.say('Hi!'); tars.say("Let's create awesome markup!"); } tars.say( 'You can find more info about TARS at ' + gutil.colors.cyan('"https://github.com/tars/tars/blob/master/README.md"'), ); if (tars.cli) { tars.say( 'Run the command ' + gutil.colors.cyan('"tars --help"') + ' to see all avalible options and commands.', ); tars.say('Start your work with ' + gutil.colors.cyan('"tars dev"') + '.'); } else { console.log('\n'); tars.say(gutil.colors.red.bold("You've started TARS via gulp.")); tars.say(gutil.colors.red.bold('This mode is depricated for developing.')); tars.say(gutil.colors.red.bold('Please, do not use "dev" tasks in with mode.\n')); tars.say('Install tars-cli for developing.'); tars.say( 'Run the command ' + gutil.colors.cyan('"npm i -g tars-cli"') + ', to install tars-cli.', ); tars.say('More info: https://github.com/tars/tars-cli.'); console.log('\n\n'); } resolve(); }); } /** * Remove temp folders * @return {Object} Promise */ function removeTemplatesFolders() { return new Promise((resolve) => { del(['./templates']).then(() => { resolve(); }); }); } /** * Generate last screen after success applying templates */ function finishInit() { console.log( gutil.colors.black.bold('\n--------------------------------------------------------'), ); tars.say(gutil.colors.green.bold('TARS has been inited successfully!\n')); tars.say('You choose:'); tars.say(gutil.colors.cyan.bold(tars.cssPreproc.name) + ' as css-preprocessor'); tars.say(gutil.colors.cyan.bold(tars.templater.name) + ' as templater\n'); if (tars.flags['exclude-html']) { tars.say('Your templater-files were not changed'); } if (tars.flags['exclude-css']) { tars.say('Your ' + tars.templater.name + '-files were not changed'); } console.log( gutil.colors.black.bold('--------------------------------------------------------\n'), ); done(); } // Start init Promise.all([generateStartScreen(), applyTemplates('templater'), applyTemplates('preprocessor')]) .then(removeTemplatesFolders) .then(finishInit) .catch((error) => { tars.say(gutil.colors.red(error)); tars.say( 'Please, repost with message and the stack trace to developer tars.builder@gmail.com', ); console.error(error.stack); done(); }); }), ); }; ================================================ FILE: tars/tasks/services/remove-init-fs.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const del = tars.packages.del; const staticFolderName = tars.config.fs.staticFolderName; const staticFolderPath = `markup/${staticFolderName}`; const componentsFolderPath = `./markup/${tars.config.fs.componentsFolderName}`; const pathsToDel = [ `${staticFolderPath}/js/framework`, `${staticFolderPath}/js/libraries`, `${staticFolderPath}/js/plugins`, `${staticFolderPath}/${tars.config.fs.imagesFolderName}/`, `${staticFolderPath}/fonts/`, `${staticFolderPath}/scss/`, `${staticFolderPath}/stylus/`, `${staticFolderPath}/less/`, `${componentsFolderPath}/_template/assets/`, `${componentsFolderPath}/_template/ie/`, `${componentsFolderPath}/head/`, `${componentsFolderPath}/footer/`, `${componentsFolderPath}/_template/_template.scss`, `${componentsFolderPath}/_template/_template.less`, `${componentsFolderPath}/_template/_template.styl`, `${componentsFolderPath}/_template/_template.html`, `${componentsFolderPath}/_template/_template.jade`, './markup/pages/', './.tmpTemplater/', './.tmpPreproc/' ]; /** * Remove inited file structure. */ module.exports = () => { return gulp.task('service:remove-init-fs', done => { del(pathsToDel).then(() => { done(); }); }); }; ================================================ FILE: tars/tasks/services/update-deps.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const gutil = tars.packages.gutil; const fs = require('fs'); /** * Update dependencies */ module.exports = () => { return gulp.task('service:update-deps', done => { const Download = tars.require('download'); const exec = require('child_process').exec; const downloadPackage = new Download({ extract: true }) .get('https://raw.githubusercontent.com/tars/tars/master/package.json') .dest('./'); tars.say( gutil.colors.yellow('This command is depricated and won\'t be supported in the future!\n') ); function downloadNewPackageJson() { fs.rename('./package.json', './_package.json', () => { downloadPackage.run(downloadError => { if (downloadError) { throw downloadError; } exec('npm i', (execError, stdout, stderr) => { console.log(stdout); console.log(stderr); console.log( gutil.colors.black.bold( '\n------------------------------------------------------------' ) ); gutil.log( gutil.colors.green('✔'), gutil.colors.green.bold('Deps update has been finished successfully!') ); console.log( gutil.colors.black.bold( '------------------------------------------------------------\n' ) ); done(execError); }); }); }); } fs.exists('./_package.json', exists => { if (exists) { fs.unlink('./_package.json', () => { downloadNewPackageJson(); }); } else { downloadNewPackageJson(); } }); }); }; ================================================ FILE: tars/tasks/services/zip-build.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; /** * Create zip archive of build */ module.exports = () => { return gulp.task('service:zip-build', done => { if (tars.config.useArchiver) { const zip = tars.require('gulp-zip'); const name = tars.packageInfo.name === 'awesome_project' ? 'build' : tars.packageInfo.name.replace(/[\s?+<>:*|"\\]/g, '_'); const version = tars.options.build.version; return gulp.src(`${tars.options.build.path}**`, { base: tars.options.build.path }) .pipe(plumber({ errorHandler(error) { notifier.error('An error occurred while creating zip-archive.', error); } })) .pipe(zip(`${name}${version}.zip`)) .pipe(gulp.dest(tars.options.build.path)) .pipe( notifier.success('Zip-archive\'s been created') ); } tars.skipTaskLog('service:zip-build', 'Archiver is not used'); done(null); }); }; ================================================ FILE: tars/user-tasks/example-task.js ================================================ 'use strict'; // This is example of task function const gulp = tars.packages.gulp; const plumber = tars.packages.plumber; const notifier = tars.helpers.notifier; const tarsConfig = tars.config; // Include browserSync, if you need to reload browser: // const browserSync = tars.packages.browserSync; /** * Task description */ module.exports = function() { return gulp.task( 'task-name', /*['required-task-name'],*/ function(done) { return ( gulp .src(/* path-string or array of path-strings to files */) .pipe( plumber({ errorHandler: function(error) { notifier.error('An error occurred while something.', error); }, }), ) // Do stuff here, like // .pipe(less()) .pipe(gulp.dest(/* path-string to destination directory. Only directory, not a file! */)) // If you need to reload browser, uncomment the row below // .pipe(browserSync.reload({ stream:true })) .pipe( // You can change text of success message notifier.success('Example task has been finished'), ) ); // You can return callback, if you can't return pipe // done(null); }, ); }; ================================================ FILE: tars/user-tasks/html/helpers/handlebars-helpers.js ================================================ 'use strict'; const Handlebars = tars.packages.handlebars; /** * You can add your own helpers to handlebarsHelpers Object * All helpers from that object will be available in templates * @type {Object} */ const handlebarsHelpers = { /** * This is an example of handlebars-helper * This helper gets string and returns it * @param {String} str Source string * @return {String} Result string */ exampleHelper: function (str) { return str; } }; module.exports = handlebarsHelpers; ================================================ FILE: tars/user-tasks/html/helpers/jade-helpers.js ================================================ 'use strict'; /** * You can add your own helpers to jadeHelpers Object * All helpers from that object will be available in templates * @type {Object} */ const jadeHelpers = { /** * This is an example of handlebars-helper * This helper gets string and returns it * @param {String} str Source string * @return {String} Result string */ exampleHelper: function (str) { return str; } }; module.exports = jadeHelpers; ================================================ FILE: tars/user-tasks/html/helpers/modify-options.js ================================================ // All options from here will override default params, // which are set in modify-html task and in minify and prettify packages. module.exports = { // All options are taken from https://github.com/kangax/html-minifier with default values minifyOpts: { }, /* eslint-disable camelcase */ // You can set any options here for html-prettify // That options will override default params for html-minify // // Supported options: // // @param {Boolean} indent_inner_html indent and sections. Default: true // @param {Number} indent_size indentation size, default: 4 // @param {String} indent_char character to indent with, default: ' ' // @param {Number} wrap_line_length maximum amount of characters per line (0 = disable). Default: 250 // @param {String} brace_style 'collapse' | 'expand' | 'end-expand' // put braces on the same line as control statements (default), // or put braces on own line (Allman / ANSI style), // or just put end braces on own line. Default: 'collapse' // @param {Array} unformatted list of tags, that shouldn't be reformatted, // defaults to inline tags. Default: all inline tags. // @param {String} indent_scripts 'keep' | 'separate' | 'normal'. Default: normal. // @param {Boolean} preserve_newlines whether existing line breaks before elements should be preserved // Only works before elements, not inside tags or for text. // Default: true. // @param {Number} max_preserve_newlines maximum number of line breaks to be preserved in one chunk // Default: unlimited // @param {Boolean} indent_handlebars format and indent {{#foo}} and {{/foo}}. Default: false prettifyOpts: { } /* eslint-enable camelcase */ }; ================================================ FILE: tars/user-tasks/html/helpers/pug-helpers.js ================================================ 'use strict'; /** * You can add your own helpers to pugHelpers Object * All helpers from that object will be available in templates * @type {Object} */ const pugHelpers = { /** * This is an example of handlebars-helper * This helper gets string and returns it * @param {String} str Source string * @return {String} Result string */ exampleHelper: function (str) { return str; } }; module.exports = pugHelpers; ================================================ FILE: tars/user-watchers/example-watcher.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const gutil = tars.packages.gutil; const chokidar = tars.packages.chokidar; const watcherLog = tars.helpers.watcherLog; /** * This is an example of watcher */ module.exports = function () { return chokidar.watch( '/* String of path pattern or array of strings */', Object.assign(tars.options.watch, { // Options set bellow will override default from tars.options.watch // If you need default options, you can use just tars.options.watch ignored: '/* String of path pattern or array of strings to ignore. If nothing to igonre — just set it with empty string */', persistent: /* Boolean, true by default*/, ignoreInitial: /* Boolean, true by default*/ }) ).on('all', function (event, watchedPath) { watcherLog(event, watchedPath); // You could start as many tasks as you need runSequence(/* Task name (String) to start */); }); }; ================================================ FILE: tars/watchers/css/common-css.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const watcherLog = tars.helpers.watcherLog; const cssPreprocFolderPath = `markup/${tars.config.fs.staticFolderName}/${tars.cssPreproc.name}`; const globsToWatch = [ `${cssPreprocFolderPath}/**/*.${tars.cssPreproc.ext}`, `${cssPreprocFolderPath}/**/*.css`, ]; /** * Watcher for all scss(less or stylus)-files */ module.exports = () => { return tars.packages.chokidar .watch( globsToWatch, Object.assign(tars.options.watch, { ignored: [`${cssPreprocFolderPath}/separate-css/**/*.css`], }), ) .on('all', (event, watchedPath) => { watcherLog(event, watchedPath); runSequence('css:compile-css'); if (tars.flags.ie8 || tars.flags.ie) { runSequence('css:compile-css-for-ie8'); } if (tars.flags.ie9 || tars.flags.ie) { runSequence('css:compile-css-for-ie9'); } }); }; ================================================ FILE: tars/watchers/css/ie8-css.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const watcherLog = tars.helpers.watcherLog; /** * Watcher for ie8 stylies */ module.exports = () => { if (tars.flags.ie8 || tars.flags.ie) { return tars.packages.chokidar .watch( [ `markup/${tars.config.fs.componentsFolderName}/**/ie8.${tars.cssPreproc.ext}`, `markup/${tars.config.fs.componentsFolderName}/**/ie8.css`, ], tars.options.watch, ) .on('all', (event, watchedPath) => { watcherLog(event, watchedPath); runSequence('css:compile-css-for-ie8'); }); } return false; }; ================================================ FILE: tars/watchers/css/ie9-css.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const watcherLog = tars.helpers.watcherLog; /** * Watcher for ie9 stylies */ module.exports = () => { if (tars.flags.ie9 || tars.flags.ie) { return tars.packages.chokidar .watch( [ `markup/${tars.config.fs.componentsFolderName}/**/ie9.${tars.cssPreproc.ext}`, `markup/${tars.config.fs.componentsFolderName}/**/ie9.css`, ], tars.options.watch, ) .on('all', (event, watchedPath) => { watcherLog(event, watchedPath); runSequence('css:compile-css-for-ie9'); }); } return false; }; ================================================ FILE: tars/watchers/css/modules-css.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const watcherLog = tars.helpers.watcherLog; /** * Watch for components' css-files */ module.exports = () => { return tars.packages.chokidar .watch( `markup/${tars.config.fs.componentsFolderName}/**/*.${tars.cssPreproc.ext}`, Object.assign(tars.options.watch, { ignored: [ `markup/${tars.config.fs.componentsFolderName}/**/ie8.${tars.cssPreproc.ext}`, `markup/${tars.config.fs.componentsFolderName}/**/ie9.${tars.cssPreproc.ext}`, `markup/${tars.config.fs.componentsFolderName}/**/ie8.css`, `markup/${tars.config.fs.componentsFolderName}/**/ie9.css`, ], }), ) .on('all', (event, watchedPath) => { watcherLog(event, watchedPath); runSequence('css:compile-css'); if (tars.flags.ie8 || tars.flags.ie) { runSequence('css:compile-css-for-ie8'); } if (tars.flags.ie9 || tars.flags.ie) { runSequence('css:compile-css-for-ie9'); } }); }; ================================================ FILE: tars/watchers/js/all.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const watcherLog = tars.helpers.watcherLog; const jsFolderPath = 'markup/' + tars.config.fs.staticFolderName + '/js'; /** * Watcher for js-files before and after components js */ module.exports = () => { if (tars.config.js.workflow === 'concat') { let jsPathToWatch = []; if (tars.config.js.jsPathsToConcatBeforeModulesJs.length) { jsPathToWatch = jsPathToWatch.concat(tars.config.js.jsPathsToConcatBeforeModulesJs); } if (tars.config.js.jsPathsToConcatAfterModulesJs.length) { jsPathToWatch = jsPathToWatch.concat(tars.config.js.jsPathsToConcatAfterModulesJs); } jsPathToWatch.push( `${jsFolderPath}/framework/**/*.js`, `${jsFolderPath}/libraries/**/*.js`, `${jsFolderPath}/plugins/**/*.js`, `markup/${tars.config.fs.componentsFolderName}/**/*.js`, ); return tars.packages.chokidar .watch( jsPathToWatch, Object.assign(tars.options.watch, { ignored: `markup/${tars.config.fs.componentsFolderName}/**/data/data.js`, }), ) .on('all', (event, watchedPath) => { watcherLog(event, watchedPath); runSequence('js:processing'); }); } return false; }; ================================================ FILE: tars/watchers/move/assets.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); /** * Watcher for images in assets dir of components */ module.exports = () => { return tars.packages.chokidar .watch( `markup/${tars.config.fs.componentsFolderName}/**/assets/*.*`, Object.assign(tars.options.watch, { ignored: `markup/${tars.config.fs.componentsFolderName}/**/assets/*.tmp`, }), ) .on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); runSequence('other:move-assets', () => {}); }); }; ================================================ FILE: tars/watchers/move/content-img.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const imagesFolderPath = `markup/${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}`; /** * Watcher for images in assets dir of components */ module.exports = () => { return tars.packages.chokidar .watch( `${imagesFolderPath}/content/**/*.*`, Object.assign(tars.options.watch, { ignored: `${imagesFolderPath}/content/**/*.tmp`, }), ) .on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); runSequence('images:move-content-img'); }); }; ================================================ FILE: tars/watchers/move/fonts.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); /** * Watcher for font files */ module.exports = () => { return tars.packages.chokidar .watch(`markup/${tars.config.fs.staticFolderName}/fonts/**/*.*`, tars.options.watch) .on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); runSequence('other:move-fonts'); }); }; ================================================ FILE: tars/watchers/move/general-img.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const imagesFolderPath = `markup/${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}`; /** * Watcher for general images */ module.exports = () => { return tars.packages.chokidar .watch( `${imagesFolderPath}/general/**/*.*`, Object.assign(tars.options.watch, { ignored: `${imagesFolderPath}/general/**/*.tmp`, }), ) .on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); runSequence('images:move-general-img'); }); }; ================================================ FILE: tars/watchers/move/misc-files.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); /** * Watcher for misc files */ module.exports = () => { return tars.packages.chokidar .watch( `markup/${tars.config.fs.staticFolderName}/misc/**/*.*`, Object.assign(tars.options.watch, { ignored: `markup/${tars.config.fs.staticFolderName}/misc/**/*.tmp`, }), ) .on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); runSequence('other:move-misc-files'); }); }; ================================================ FILE: tars/watchers/move/plugins-img.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const imagesFolderPath = `markup/${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}`; /** * Watcher for images of plugins */ module.exports = () => { return tars.packages.chokidar .watch( `${imagesFolderPath}/plugins/**/*.*`, Object.assign(tars.options.watch, { ignored: `${imagesFolderPath}/plugins/**/*.tmp`, }), ) .on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); runSequence('images:move-plugins-img'); }); }; ================================================ FILE: tars/watchers/move/separate-css.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); /** * Watcher for separate Js files files */ module.exports = () => { return tars.packages.chokidar .watch( `markup/${tars.config.fs.staticFolderName}/${tars.cssPreproc.name}/separate-css/**/*.css`, tars.options.watch, ) .on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); runSequence('css:move-separate'); }); }; ================================================ FILE: tars/watchers/move/separate-js.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); /** * Watcher for separate Js files files */ module.exports = () => { return tars.packages.chokidar .watch(`markup/${tars.config.fs.staticFolderName}/js/separate-js/**/*.js`, tars.options.watch) .on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); runSequence('js:move-separate'); }); }; ================================================ FILE: tars/watchers/sprite/png-sprites.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); /** * Watcher for images for sprite (png) */ module.exports = () => { return tars.packages.chokidar .watch( `markup/${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}/sprite/**/*.png`, tars.options.watch, ) .on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); runSequence('css:make-sprite', () => {}); }); }; ================================================ FILE: tars/watchers/sprite/svg-sprites.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); /** * Watcher for images for sprite (svg) */ module.exports = () => { if (tars.config.svg.active && tars.config.svg.workflow === 'sprite') { return tars.packages.chokidar.watch( `markup/${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}/svg/**/*.svg`, tars.options.watch ).on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); if (tars.flags.ie8 || tars.flags.ie) { runSequence( ['images:minify-svg', 'images:raster-svg'], ['css:make-fallback-for-svg', 'css:make-sprite-for-svg'], () => {} ); } else { runSequence( 'images:minify-svg', 'css:make-sprite-for-svg', () => {} ); } }); } return false; }; ================================================ FILE: tars/watchers/sprite/symbols.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); /** * Watcher for images for symbols (svg) */ module.exports = () => { if (tars.config.svg.active && tars.config.svg.workflow === 'symbols') { return tars.packages.chokidar.watch( `markup/${tars.config.fs.staticFolderName}/${tars.config.fs.imagesFolderName}/svg/**/*.svg`, tars.options.watch ).on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); runSequence( 'images:minify-svg', 'images:make-symbols-sprite', 'html:concat-mocks-data', 'html:compile-templates', () => {} ); }); } return false; }; ================================================ FILE: tars/watchers/templates/data-files.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const templaterName = require(`${tars.root}/helpers/get-templater-name`)(tars.config.templater.toLowerCase()); /** * Watcher for data-files of components */ module.exports = () => { return tars.packages.chokidar.watch( `markup/${tars.config.fs.componentsFolderName}/**/data/data.js`, tars.options.watch ).on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); // Remove cache for components with changed data-files if ((templaterName === 'jade' || templaterName === 'pug') && tars.packages.cache.caches && tars.packages.cache.caches.templates) { const templateToRecompile = watchedPath.split('/data/data.js').shift(); for (let cacheKey in tars.packages.cache.caches.templates) { if (cacheKey.indexOf(templateToRecompile) > -1) { delete tars.packages.cache.caches.templates[cacheKey]; } } } runSequence( 'html:concat-mocks-data', 'html:compile-templates', () => {} ); }); }; ================================================ FILE: tars/watchers/templates/page-modules.js ================================================ 'use strict'; const gulp = tars.packages.gulp; const runSequence = tars.packages.runSequence.use(gulp); const path = require('path'); const filesToWatch = [ `markup/pages/**/*.${tars.templater.ext}`, `markup/${tars.config.fs.componentsFolderName}/**/*.${tars.templater.ext}`, ]; /** * Watcher for templates-files of components and pages */ module.exports = () => { return tars.packages.chokidar .watch( filesToWatch, Object.assign(tars.options.watch, { ignored: `markup/pages/**/_*.${tars.templater.ext}`, }), ) .on('all', (event, watchedPath) => { tars.helpers.watcherLog(event, watchedPath); if ( watchedPath.indexOf(`markup${path.sep}pages`) > -1 && (event === 'unlink' || event === 'add') ) { runSequence('html:concat-mocks-data', 'html:compile-templates', () => {}); } else { runSequence('html:compile-templates', () => {}); } }); }; ================================================ FILE: tars-config.js ================================================ 'use strict'; module.exports = { ///////////////////// // MUTABLE OPTIONS //////////////////////////////// // YOU CAN CHANGE THIS OPTIONS ALL THE TIME // // // // You need to restart builder to apply options. // /////////////////////////////////////////////////// /** * Postprocessors for TARS * @type {Array} * Example: * * postcss: [ * { * name: 'postcss-short', * options: { * deny: ['text'] * } * } * ] */ postcss: [], svg: { active: true, // symbols, sprite workflow: 'sprite', symbolsConfig: { // separate-file, separate-file-with-link, inject loadingType: 'inject', usePolyfillForExternalSymbols: true, pathToExternalSymbolsFile: '' } }, css: { // concat, manual workflow: 'concat' }, js: { // concat, modular workflow: 'concat', // Only webpack is available right now bundler: 'webpack', /** * Use linting of js-files * @type {Boolean} */ lint: true, /** * Use babel for ES6(ES7-ESNext) syntax support * @type {Boolean} */ useBabel: true, /** * Remove console.log and debugger from js code in release mode * @type {Boolean} */ removeConsoleLog: true, // Special config for webpack webpack: { useHMR: false, /** * Automatically loaded modules. * Module (value) is loaded when the identifier (key) is used as free variable in a module. * The identifier is filled with the exports of the loaded module. * Example: {$: "jquery"} or {React: 'react'} * @type {Object} */ providePlugin: {} }, /** * Path-strings to js-files, which have to be included before modules' js-files * Example: ['./markup/controller/** /*.js'] * @type {Array} */ jsPathsToConcatBeforeModulesJs: [], /** * Lint additional js before modules * @type {Boolean} */ lintJsCodeBeforeModules: false, /** * Path-strings to js-files, which have to be included before modules' js-files * @type {Array} */ jsPathsToConcatAfterModulesJs: [], /** * Lint additional js after modules * @type {Boolean} */ lintJsCodeAfterModules: false }, /** * Write sourcemaps * @type {Object} * * active – is sourcemaps active * inline – use inline sourcemaps or in separate file */ sourcemaps: { js: { active: true, inline: true }, css: { active: true, inline: true } }, /** * Config for Notify module * @type {Object} */ notifyConfig: { /** * Do you need to use notify? * @type {Boolean} */ useNotify: true, /** * Title for notifier * @type {String} */ title: 'TARS notification', /** * Sounds notifactions * String (name of system sound) or undefined, if you don't need to hear any sounds * @type {Object} */ sounds: { /** * Sound after successfull finishing of task * @type {String, undefined} * For example 'Glass' in OS X */ onSuccess: undefined, /** * Sound after failed finishing of task * @type {String, undefined} * For example 'Glass' in OS X */ onError: undefined }, /** * Label for timestamp of task finishing time * @type {String} */ taskFinishedText: 'Task finished at: ' }, /** * Minify result html in build version * If is set to false, compiled html will be prettified * @type {Boolean} */ minifyHtml: false, /** * TARS will generate relative path from current page * to static files in case of true value * @type {Boolean} */ generateStaticPath: true, /** * Path to dev version of project * Could be like '../../../dev/' or absolute path * If you change the value do not forget to change the 'baseDir' in the file 'plugins-config.json' and .gitignore * The slash after the name should stand * @type {String} */ devPath: './dev/', /** * Path to build version of project * Could be like '../../../builds/' or absolute path * The slash after the name should stand * @type {String} */ buildPath: './builds/', /** * Use build versioning * Build version is a date ot building * @type {Boolean} */ useBuildVersioning: true, /** * Use archiver for your build * @type {Boolean} */ useArchiver: true, /** * Set ulimit. Topical for Linux-family OS and OSX. * @type {Number} */ ulimit: 4096, ////////////////////////////////////////////// ////////////////////////////////////////////// //////////////////////////////////////////////////////// // YOU CAN CHANGE THIS OPTIONS AND USE REINIT // // // // Options for technologies, which you'd like to use. // //////////////////////////////////////////////////////// /** * Templater * Available 'pug', 'jade' and 'handlebars' * @type {String} */ templater: 'handlebars', /** * Css-preprocessor * Available 'scss', 'less' or 'stylus' * .sass extension is supported if cssPreprocessor is 'scss' * @type {String} */ cssPreprocessor: 'scss', /** * What kind of size of images are you going to use. * 96 — 1 dppx (regular) * 192 — 2 dppx (retina) * 288 — 3 dppx (nexus 5, for example) * 384 - 4 dppx (nexus 6, for example) * Example if using for all displays: usePpi: [96, 192, 288, 384] * You can change with options not only on init or reinit, * but at with time you have to create new directories * and delete unused. * @type {Array} */ useImagesForDisplayWithDpi: [96], //////////////////////////////////////////////// //////////////////////////////////////////////// //////////////////////////////////////////////////////// // You have to change with options after manually // // renaming static and img folder // // // // Do not rename these dirs before reinit // //////////////////////////////////////////////////////// /** * File structure settings * @type {Object} */ fs: { /** * Name of folder with static files, such *.css, *.js and so on * 'static' by default * @type {String} */ staticFolderName: 'static', /** * Name of folder with images * 'img' by default * @type {String} */ imagesFolderName: 'img', /** * Name of folder with modules * 'modules' by default * @type {String} */ componentsFolderName: 'components' } //////////////////////////////////////////////////// //////////////////////////////////////////////////// }; ================================================ FILE: tars.json ================================================ { "name": "tars", "version": "1.15.1", "description": "Powerfull markup builder" } ================================================ FILE: templates/handlebars/markup/components/_template/_template.html ================================================ ================================================ FILE: templates/handlebars/markup/components/default_component_scheme.json ================================================ { "folders": [ { "name": "data", "files": [ { "name": "data.js", "content": "var data = {__componentName__: {}}" } ] } ], "files": [ { "name": "__componentName__.__templateExtension__", "content": "
" }, { "name": "__componentName__.__cssExtension__", "content": ".__componentName__ {}" }, { "name": "__componentName__.js", "content": "" } ] } ================================================ FILE: templates/handlebars/markup/components/example/example.html ================================================

Hello, World!

================================================ FILE: templates/handlebars/markup/components/footer/footer.html ================================================ ================================================ FILE: templates/handlebars/markup/components/head/data/data.js ================================================ head: { defaults: { title: 'default title', useSocialMetaTags: true } } ================================================ FILE: templates/handlebars/markup/components/head/head.html ================================================ {{title}} {{#if useSocialMetaTags}} {{/if}} ================================================ FILE: templates/handlebars/markup/pages/_template.html ================================================ {{> head/head head.defaults}} %=symbols=%
{{> footer/footer}}
================================================ FILE: templates/handlebars/markup/pages/index.html ================================================ {{> head/head head.defaults}} %=symbols=%
{{> example/example}}
{{> footer/footer}}
================================================ FILE: templates/jade/markup/components/_template/_template.jade ================================================ mixin _template(data) ================================================ FILE: templates/jade/markup/components/default_component_scheme.json ================================================ { "folders": [ { "name": "data", "files": [ { "name": "data.js", "content": "var data = {__componentName__: {}}" } ] } ], "files": [ { "name": "__componentName__.__templateExtension__", "content": "mixin __componentName__(data)\n .__componentName__" }, { "name": "__componentName__.__cssExtension__", "content": ".__componentName__ {}" }, { "name": "__componentName__.js", "content": "" } ] } ================================================ FILE: templates/jade/markup/components/example/example.jade ================================================ mixin example(data) h1 | Hello, World! ================================================ FILE: templates/jade/markup/components/footer/footer.jade ================================================ mixin footer(data) footer.footer ================================================ FILE: templates/jade/markup/components/head/data/data.js ================================================ head: { defaults: { title: 'default title', useSocialMetaTags: true } } ================================================ FILE: templates/jade/markup/components/head/head.jade ================================================ mixin head(data) meta(charset="utf-8") meta(http-equiv="x-ua-compatible", content="ie=edge") title #{data.title} meta(content="", name="description") meta(content="", name="keywords") meta(name="viewport", content="width=device-width, initial-scale=1.0") meta(content="telephone=no", name="format-detection") //- This make sence for mobile browsers. It means, that content has been optimized for mobile browsers meta(name="HandheldFriendly", content="true") | | | if data.useSocialMetaTags meta(property="og:title", content="#{data.title}") meta(property="og:title", content="") meta(property="og:url", content="") meta(property="og:description", content="") meta(property="og:image", content="") meta(property="og:image:type", content="image/jpeg") meta(property="og:image:width", content="500") meta(property="og:image:height", content="300") meta(property="twitter:description", content="") link(rel="image_src", href="") link(rel="icon" type="image/x-icon" href="favicon.ico") script. (function(H){H.className=H.className.replace(/\bno-js\b/,'js')})(document.documentElement) | ================================================ FILE: templates/jade/markup/pages/_template.jade ================================================ doctype html html(class="no-js", lang="ru") include ../components/head/head include ../components/footer/footer head +head(head.defaults) body.page |%=symbols=% section.page__wrapper //- Include your components here .page__buffer .page__footer +footer() script(src='%=static=%js/separate-js/svg4everybody.min.js') script svg4everybody(); //- Main scripts. You can replace it, but I recommend you to leave it here script(src='%=static=%js/main%=hash=%%=min=%.js') ================================================ FILE: templates/jade/markup/pages/index.jade ================================================ doctype html html(class="no-js", lang="ru") include ../components/head/head include ../components/example/example include ../components/footer/footer head +head(head.defaults) body.page |%=symbols=% section.page__wrapper //- Include your components here +example() .page__buffer .page__footer +footer() script(src='%=static=%js/separate-js/svg4everybody.min.js') script svg4everybody(); //- Main scripts. You can replace it, but I recommend you to leave it here script(src='%=static=%js/main%=hash=%%=min=%.js') ================================================ FILE: templates/less/markup/components/_template/_template.less ================================================ ================================================ FILE: templates/less/markup/static/less/GUI.less ================================================ // GUI stylies of the project // For example, styles of the links, buttons and so on. ================================================ FILE: templates/less/markup/static/less/common.less ================================================ // Common styles of the project html, body { height: 100%; } .page { // Стили для body } .page__wrapper { min-height: 100%; margin-bottom: -50px; } * html .page__wrapper { height: 100%; } .page__buffer { height: 50px; } ================================================ FILE: templates/less/markup/static/less/entry/built-in-partials/_service-ie8.less ================================================ /* Some styles, which is used for correct sprite-generation, vars, mixins and etc */ /* Please, do not edit with file! */ /* This file can be overwritten by update-project! */ /* Mixins, which are specific for current project */ @import '../../mixins.less'; /* Mixins and vars for sprite generation */ @import '../../sprites-less/sprite_96.less'; @import '../../sprites-less/sprite-png.less'; @import '../../sprites-less/svg-fallback-sprite.less'; @import '../../sprites-less/sprite-png-ie.less'; /* Less for used fonts */ @import '../../fonts.less'; /* Vars, which are specific for current project */ @import '../../vars.less'; /* Styles for UI-elements */ @import '../../GUI.less'; /* Common styles for current project */ @import '../../common.less'; ================================================ FILE: templates/less/markup/static/less/entry/built-in-partials/_service.less ================================================ /* Some styles, which is used for correct sprite-generation, vars, mixins and etc */ /* Please, do not edit with file! */ /* This file can be overwritten by update-project! */ /* Mixins, which are specific for current project */ @import '../../mixins.less'; /* Mixins and vars for sprite generation */ @import '../../sprites-less/sprite_96.less'; @import '../../sprites-less/sprite-png.less'; @import '../../sprites-less/svg-sprite.less'; /* Less for used fonts */ @import '../../fonts.less'; /* Vars, which are specific for current project */ @import '../../vars.less'; /* Styles for UI-elements */ @import '../../GUI.less'; /* Common styles for current project */ @import '../../common.less'; ================================================ FILE: templates/less/markup/static/less/entry/ie/main_ie8.less ================================================ @import '../../normalize.less'; /* Libraries, which is used in current project. */ @import '../partials/_libraries.less'; /* Libraries, which is used in current project. */ @import '../built-in-partials/_service-ie8.less'; /* Plugins, which is used in current project. */ @import '../partials/_plugins.less'; /* Components, which is used in current project. */ @import '../partials/_components.less'; @import '../partials/_components-ie8.less'; /* Additional style files. */ @import '../../etc/etc.less'; ================================================ FILE: templates/less/markup/static/less/entry/ie/main_ie9.less ================================================ @import '../../normalize.less'; /* Libraries, which is used in current project. */ @import '../partials/_libraries.less'; /* Libraries, which is used in current project. */ @import '../built-in-partials/_service.less'; /* Plugins, which is used in current project. */ @import '../partials/_plugins.less'; /* Components, which is used in current project. */ @import '../partials/_components.less'; @import '../partials/_components-ie9.less'; /* Additional style files. */ @import '../../etc/etc.less'; ================================================ FILE: templates/less/markup/static/less/entry/main.less ================================================ @import '../normalize.less'; /* Libraries, which is used in current project. */ @import 'partials/_libraries.less'; /* Libraries, which is used in current project. */ @import 'built-in-partials/_service.less'; /* Plugins, which is used in current project. */ @import 'partials/_plugins.less'; /* Components, which is used in current project. */ @import 'partials/_components.less'; /* Additional style files. */ @import '../etc/etc.less'; ================================================ FILE: templates/less/markup/static/less/entry/partials/_components-ie8.less ================================================ ================================================ FILE: templates/less/markup/static/less/entry/partials/_components-ie9.less ================================================ ================================================ FILE: templates/less/markup/static/less/entry/partials/_components.less ================================================ // @import 'components/_template/_template.less'; ================================================ FILE: templates/less/markup/static/less/entry/partials/_libraries.less ================================================ ================================================ FILE: templates/less/markup/static/less/entry/partials/_plugins.less ================================================ ================================================ FILE: templates/less/markup/static/less/etc/etc.less ================================================ ================================================ FILE: templates/less/markup/static/less/fonts.less ================================================ /* Your custom fonts here */ /* Example @font-face { font-family: 'CustomFont'; src: url('../fonts/Custom-Font.eot'); src: url('../fonts/Custom-Font.eot?#iefix') format('embedded-opentype'), url('../fonts/Custom-Font.woff') format('woff'), url('../fonts/Custom-Font.svg#custom_font') format('svg'); font-weight: 400; // For normal width. It could has another value font-style: normal; // Also could has another value } // Var for using custom font @CustomFont: 'CustomFont', Helvetica, Arial, sans-serif; */ ================================================ FILE: templates/less/markup/static/less/libraries/library-sample.less ================================================ ================================================ FILE: templates/less/markup/static/less/mixins.less ================================================ // Mixins. .nl() { margin: 0; padding: 0; text-indent: 0; list-style: none; list-style-position: outside; } .cf() { &:before, &:after { display: table; content: ""; } &:after { clear: both; } .lt-ie8 & { zoom: 1; } } .blocks-justify() { text-align: justify; text-justify: newspaper; } // You can add your own mixins here: ================================================ FILE: templates/less/markup/static/less/normalize.less ================================================ /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document ========================================================================== */ /** * 1. Correct the line height in all browsers. * 2. Prevent adjustments of font size after orientation changes in iOS. */ html { line-height: 1.15; /* 1 */ -webkit-text-size-adjust: 100%; /* 2 */ } /* Sections ========================================================================== */ /** * Remove the margin in all browsers. */ body { margin: 0; } /** * Render the `main` element consistently in IE. */ main { display: block; } /** * Correct the font size and margin on `h1` elements within `section` and * `article` contexts in Chrome, Firefox, and Safari. */ h1 { font-size: 2em; margin: 0.67em 0; } /* Grouping content ========================================================================== */ /** * 1. Add the correct box sizing in Firefox. * 2. Show the overflow in Edge and IE. */ hr { box-sizing: content-box; /* 1 */ height: 0; /* 1 */ overflow: visible; /* 2 */ } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ pre { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /* Text-level semantics ========================================================================== */ /** * Remove the gray background on active links in IE 10. */ a { background-color: transparent; } /** * 1. Remove the bottom border in Chrome 57- * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. */ abbr[title] { border-bottom: none; /* 1 */ text-decoration: underline; /* 2 */ text-decoration: underline dotted; /* 2 */ } /** * Add the correct font weight in Chrome, Edge, and Safari. */ b, strong { font-weight: bolder; } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ code, kbd, samp { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /** * Add the correct font size in all browsers. */ small { font-size: 80%; } /** * Prevent `sub` and `sup` elements from affecting the line height in * all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.5em; } /* Embedded content ========================================================================== */ /** * Remove the border on images inside links in IE 10. */ img { border-style: none; } /* Forms ========================================================================== */ /** * 1. Change the font styles in all browsers. * 2. Remove the margin in Firefox and Safari. */ button, input, optgroup, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 1 */ line-height: 1.15; /* 1 */ margin: 0; /* 2 */ } /** * Show the overflow in IE. * 1. Show the overflow in Edge. */ button, input { /* 1 */ overflow: visible; } /** * Remove the inheritance of text transform in Edge, Firefox, and IE. * 1. Remove the inheritance of text transform in Firefox. */ button, select { /* 1 */ text-transform: none; } /** * Correct the inability to style clickable types in iOS and Safari. */ button, [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; } /** * Remove the inner border and padding in Firefox. */ button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; } /** * Restore the focus styles unset by the previous rule. */ button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; } /** * Correct the padding in Firefox. */ fieldset { padding: 0.35em 0.75em 0.625em; } /** * 1. Correct the text wrapping in Edge and IE. * 2. Correct the color inheritance from `fieldset` elements in IE. * 3. Remove the padding so developers are not caught out when they zero out * `fieldset` elements in all browsers. */ legend { box-sizing: border-box; /* 1 */ color: inherit; /* 2 */ display: table; /* 1 */ max-width: 100%; /* 1 */ padding: 0; /* 3 */ white-space: normal; /* 1 */ } /** * Add the correct vertical alignment in Chrome, Firefox, and Opera. */ progress { vertical-align: baseline; } /** * Remove the default vertical scrollbar in IE 10+. */ textarea { overflow: auto; } /** * 1. Add the correct box sizing in IE 10. * 2. Remove the padding in IE 10. */ [type="checkbox"], [type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** * Correct the cursor style of increment and decrement buttons in Chrome. */ [type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; } /** * 1. Correct the odd appearance in Chrome and Safari. * 2. Correct the outline style in Safari. */ [type="search"] { -webkit-appearance: textfield; /* 1 */ outline-offset: -2px; /* 2 */ } /** * Remove the inner padding in Chrome and Safari on macOS. */ [type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** * 1. Correct the inability to style clickable types in iOS and Safari. * 2. Change font properties to `inherit` in Safari. */ ::-webkit-file-upload-button { -webkit-appearance: button; /* 1 */ font: inherit; /* 2 */ } /* Interactive ========================================================================== */ /* * Add the correct display in Edge, IE 10+, and Firefox. */ details { display: block; } /* * Add the correct display in all browsers. */ summary { display: list-item; } /* Misc ========================================================================== */ /** * Add the correct display in IE 10+. */ template { display: none; } /** * Add the correct display in IE 10. */ [hidden] { display: none; } ================================================ FILE: templates/less/markup/static/less/plugins/sample-plugin.less ================================================ // This is a sample file for scss for plugins // Each plugin's scss code have to be in separate files ================================================ FILE: templates/less/markup/static/less/separate-css/separate-css-sample.css ================================================ ================================================ FILE: templates/less/markup/static/less/sprite-generator-templates/less.sprite.mustache ================================================ { // Default options 'functions': true } {{#items}} @{{name}}: {{px.x}} {{px.y}} {{px.offset_x}} {{px.offset_y}} {{px.width}} {{px.height}} {{px.total_width}} {{px.total_height}} '{{{escaped_image}}}'; {{/items}} {{#options.functions}} .sprite-position(@sprite) { @sprite-offset-x: ~`"@{sprite}".split(', ')[2]`; @sprite-offset-y: ~`"@{sprite}".split(', ')[3]`; background-position: @sprite-offset-x @sprite-offset-y; } .sprite-image(@sprite) { {{! DEV: We perform a slice due to a trailing brace from string coercion of arrays }} @sprite-image: ~`'%=static=%png-sprite/96dpi/' + "@{sprite}".split(', ')[8].replace(']', '').replace(/\'/g, '')`; background-image: url(@sprite-image); } .sprite-mixin-template(@sprite) { .sprite-image(@sprite); .sprite-position(@sprite); width: ~`"@{sprite}".split(', ')[4]`; height: ~`"@{sprite}".split(', ')[5]`; } .bg-template(@sprite, @repeat: no-repeat) { .sprite-mixin-template(@sprite); @sprite-total-width: ~`"@{sprite}".split(', ')[6]`; @sprite-total-height: ~`"@{sprite}".split(', ')[7]`; background-size: @sprite-total-width, @sprite-total-height; background-repeat: @repeat; } .highDpiMedia(@sprite) { {{#options.dpi192}} @media screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min-resolution: 192dpi), only screen and ( min-resolution: 2dppx), only screen and (min-device-pixel-ratio: 2) { @sprite-image: ~`'%=static=%png-sprite/192dpi/' + "@{sprite}".split(', ')[8].replace(']', '').replace(/\'/g, '')`; background-image: url(@sprite-image); } {{/options.dpi192}} {{#options.dpi288}} @media screen and (-webkit-min-device-pixel-ratio: 3), only screen and ( min-resolution: 288dpi), only screen and ( min-resolution: 3dppx), only screen and (min-device-pixel-ratio: 3) { @sprite-image: ~`'%=static=%png-sprite/288dpi/' + "@{sprite}".split(', ')[8].replace(']', '').replace(/\'/g, '')`; background-image: url(@sprite-image); } {{/options.dpi288}} {{#options.dpi384}} @media screen and (-webkit-min-device-pixel-ratio: 4), only screen and ( min-resolution: 384dpi), only screen and ( min-resolution: 4dppx), only screen and (min-device-pixel-ratio: 4) { @sprite-image: ~`'%=static=%png-sprite/384dpi/' + "@{sprite}".split(', ')[8].replace(']', '').replace(/\'/g, '')`; background-image: url(@sprite-image); } {{/options.dpi384}} } {{/options.functions}} ================================================ FILE: templates/less/markup/static/less/sprite-generator-templates/less.svg-fallback-sprite.mustache ================================================ { // Default options 'functions': true } {{#items}} @{{name}}: {{px.x}} {{px.y}} {{px.offset_x}} {{px.offset_y}} {{px.width}} {{px.height}} {{px.total_width}} {{px.total_height}} '{{{escaped_image}}}' '{{{name}}}'; {{/items}} {{#options.functions}} .svg-sprite-position(@svg-sprite) { @svg-sprite-offset-x: ~`"@{svg-sprite}".split(', ')[2]`; @svg-sprite-offset-y: ~`"@{svg-sprite}".split(', ')[3]`; background-position: @svg-sprite-offset-x @svg-sprite-offset-y; } .svg-sprite-image(@svg-sprite) { @svg-sprite-image-url: ~`'../img/rastered-svg-sprite/' + "@{svg-sprite}".split(', ')[8].replace(']', '').replace(/\'/g, '')`; background-image: url(@svg-sprite-image-url); } .bg-svg(@svg-sprite, @repeat: no-repeat) { .svg-sprite-image(@svg-sprite); .svg-sprite-position(@svg-sprite); width: ~`"@{svg-sprite}".split(', ')[4]`; height: ~`"@{svg-sprite}".split(', ')[5]`; background-repeat: @repeat; } {{/options.functions}} ================================================ FILE: templates/less/markup/static/less/sprite-generator-templates/less.svg-sprite.mustache ================================================ {{#sprites}} @{{fileName}}: {{x}}{{units}} {{y}}{{units}} {{w}}{{units}} {{h}}{{units}} {{width}}{{units}} {{height}}{{units}} '{{{cssPathSvg}}}' '{{{fileName}}}'; {{/sprites}} .svg-sprite-position(@svg-sprite) { @svg-sprite-offset-x: ~`"@{svg-sprite}".split(', ')[0].replace('[', '')`; @svg-sprite-offset-y: ~`"@{svg-sprite}".split(', ')[1]`; background-position: @svg-sprite-offset-x @svg-sprite-offset-y; } .bg-svg(@svg-sprite, @repeat: no-repeat) { background-image: url('%=static=%svg-sprite/{{imgName}}'); .svg-sprite-position(@svg-sprite); width: ~`"@{svg-sprite}".split(', ')[2]`; height: ~`"@{svg-sprite}".split(', ')[3]`; background-repeat: @repeat; } ================================================ FILE: templates/less/markup/static/less/sprites-less/sprite-png-ie.less ================================================ .bg(@sprite, @repeat: no-repeat) { .bg-template(@sprite, @repeat: no-repeat); } ================================================ FILE: templates/less/markup/static/less/sprites-less/sprite-png.less ================================================ .bg(@sprite, @repeat: no-repeat) { .bg-template(@sprite, @repeat: no-repeat); .highDpiMedia(@sprite); } ================================================ FILE: templates/less/markup/static/less/vars.less ================================================ // File for less-vars. // For example: main colors, paddings and so on. ================================================ FILE: templates/pug/markup/components/_template/_template.pug ================================================ mixin _template(data) ._template ================================================ FILE: templates/pug/markup/components/default_component_scheme.json ================================================ { "folders": [ { "name": "data", "files": [ { "name": "data.js", "content": "var data = {__componentName__: {}}" } ] } ], "files": [ { "name": "__componentName__.__templateExtension__", "content": "mixin __componentName__(data)\n .__componentName__" }, { "name": "__componentName__.__cssExtension__", "content": ".__componentName__ {}" }, { "name": "__componentName__.js", "content": "" } ] } ================================================ FILE: templates/pug/markup/components/example/example.pug ================================================ mixin example(data) h1 | Hello, World! ================================================ FILE: templates/pug/markup/components/footer/footer.pug ================================================ mixin footer(data) footer.footer ================================================ FILE: templates/pug/markup/components/head/data/data.js ================================================ head: { defaults: { title: 'default title', useSocialMetaTags: true } } ================================================ FILE: templates/pug/markup/components/head/head.pug ================================================ mixin head(data) meta(charset="utf-8") meta(http-equiv="x-ua-compatible", content="ie=edge") title #{data.title} meta(content="", name="description") meta(content="", name="keywords") meta(name="viewport", content="width=device-width, initial-scale=1.0") meta(content="telephone=no", name="format-detection") //- This make sence for mobile browsers. It means, that content has been optimized for mobile browsers meta(name="HandheldFriendly", content="true") | | | if data.useSocialMetaTags meta(property="og:title", content="#{data.title}") meta(property="og:title", content="") meta(property="og:url", content="") meta(property="og:description", content="") meta(property="og:image", content="") meta(property="og:image:type", content="image/jpeg") meta(property="og:image:width", content="500") meta(property="og:image:height", content="300") meta(property="twitter:description", content="") link(rel="image_src", href="") link(rel="icon" type="image/x-icon" href="favicon.ico") script. (function(H){H.className=H.className.replace(/\bno-js\b/,'js')})(document.documentElement) | ================================================ FILE: templates/pug/markup/pages/_template.pug ================================================ doctype html html(class="no-js", lang="ru") include ../components/head/head.pug include ../components/footer/footer.pug head +head(head.defaults) body.page |%=symbols=% section.page__wrapper //- Include your components here .page__buffer .page__footer +footer() script(src='%=static=%js/separate-js/svg4everybody.min.js') script svg4everybody(); //- Main scripts. You can replace it, but I recommend you to leave it here script(src='%=static=%js/main%=hash=%%=min=%.js') ================================================ FILE: templates/pug/markup/pages/index.pug ================================================ doctype html html(class="no-js", lang="ru") include ../components/head/head.pug include ../components/example/example.pug include ../components/footer/footer.pug head +head(head.defaults) body.page |%=symbols=% section.page__wrapper //- Include your components here +example() .page__buffer .page__footer +footer() script(src='%=static=%js/separate-js/svg4everybody.min.js') script svg4everybody(); //- Main scripts. You can replace it, but I recommend you to leave it here script(src='%=static=%js/main%=hash=%%=min=%.js') ================================================ FILE: templates/scss/markup/components/_template/_template.scss ================================================ ================================================ FILE: templates/scss/markup/static/scss/GUI.scss ================================================ // GUI stylies of the project // For example, styles of the links, buttons and so on. ================================================ FILE: templates/scss/markup/static/scss/common.scss ================================================ // Common styles of the project html, body { height: 100%; } .page { } .page__wrapper { min-height: 100%; margin-bottom: -50px; } * html .page__wrapper { height: 100%; } .page__buffer { height: 50px; } ================================================ FILE: templates/scss/markup/static/scss/entry/built-in-partials/_service-ie8.scss ================================================ /* Some styles, which is used for correct sprite-generation, vars, mixins and etc */ /* Please, do not edit with file! */ /* This file can be overwritten bu update-project! */ /* Mixins, which are specific for current project */ @import '../../mixins.scss'; /* Mixins and vars for sprite generation */ @import '../../sprites-scss/sprite_96.scss'; @import '../../sprites-scss/sprite-ie.scss'; @import '../../sprites-scss/svg-fallback-sprite.scss'; /* Scss for used fonts */ @import '../../fonts.scss'; /* Vars, which are specific for current project */ @import '../../vars.scss'; /* Styles for UI-elements */ @import '../../GUI.scss'; /* Common styles for current project */ @import '../../common.scss'; ================================================ FILE: templates/scss/markup/static/scss/entry/built-in-partials/_service.scss ================================================ /* Some styles, which is used for correct sprite-generation, vars, mixins and etc */ /* Please, do not edit with file! */ /* This file can be overwritten by update-project! */ /* Mixins, which are specific for current project */ @import '../../mixins.scss'; /* Mixins and vars for sprite generation */ @import '../../sprites-scss/sprite_96.scss'; @import '../../sprites-scss/svg-sprite.scss'; /* Scss for used fonts */ @import '../../fonts.scss'; /* Vars, which are specific for current project */ @import '../../vars.scss'; /* Styles for UI-elements */ @import '../../GUI.scss'; /* Common styles for current project */ @import '../../common.scss'; ================================================ FILE: templates/scss/markup/static/scss/entry/ie/main_ie8.scss ================================================ @import '../../normalize.scss'; /* Libraries, which is used in current project. Can be removed! */ @import '../partials/_libraries.scss'; /* Libraries, which is used in current project. Do not remove! */ @import '../built-in-partials/_service-ie8.scss'; /* Plugins, which is used in current project. Can be removed! */ @import '../partials/_plugins.scss'; /* Components, which is used in current project. Can be removed! */ @import '../partials/_components.scss'; @import '../partials/_components-ie8.scss'; /* Additional style files. Can be removed! */ @import '../../etc/etc.scss'; ================================================ FILE: templates/scss/markup/static/scss/entry/ie/main_ie9.scss ================================================ @import '../../normalize.scss'; /* Libraries, which is used in current project. Can be removed! */ @import '../partials/_libraries.scss'; /* Libraries, which is used in current project. Do not remove! */ @import '../built-in-partials/_service.scss'; /* Plugins, which is used in current project. Can be removed! */ @import '../partials/_plugins.scss'; /* Components, which is used in current project. Can be removed! */ @import '../partials/_components.scss'; @import '../partials/_components-ie9.scss'; /* Additional style files. Can be removed! */ @import '../../etc/etc.scss'; ================================================ FILE: templates/scss/markup/static/scss/entry/main.scss ================================================ @import '../normalize.scss'; /* Libraries, which is used in current project. */ @import 'partials/_libraries.scss'; /* Libraries, which is used in current project. */ @import 'built-in-partials/_service.scss'; /* Plugins, which is used in current project. */ @import 'partials/_plugins.scss'; /* Components, which is used in current project. */ @import 'partials/_components.scss'; /* Additional style files. */ @import '../etc/etc.scss'; ================================================ FILE: templates/scss/markup/static/scss/entry/partials/_components-ie8.scss ================================================ ================================================ FILE: templates/scss/markup/static/scss/entry/partials/_components-ie9.scss ================================================ ================================================ FILE: templates/scss/markup/static/scss/entry/partials/_components.scss ================================================ // @import 'components/_template/_template.scss'; ================================================ FILE: templates/scss/markup/static/scss/entry/partials/_libraries.scss ================================================ ================================================ FILE: templates/scss/markup/static/scss/entry/partials/_plugins.scss ================================================ ================================================ FILE: templates/scss/markup/static/scss/etc/etc.scss ================================================ ================================================ FILE: templates/scss/markup/static/scss/fonts.scss ================================================ /* Your custom fonts here */ /* Example @font-face { font-family: 'CustomFont'; src: url('../fonts/Custom-Font.eot'); src: url('../fonts/Custom-Font.eot?#iefix') format('embedded-opentype'), url('../fonts/Custom-Font.woff') format('woff'), url('../fonts/Custom-Font.svg#custom_font') format('svg'); font-weight: 400; // For normal width. It could has another value font-style: normal; // Also could has another value } // Var for using custom font $CustomFont: 'CustomFont', Helvetica, Arial, sans-serif; */ ================================================ FILE: templates/scss/markup/static/scss/libraries/library-sample.scss ================================================ ================================================ FILE: templates/scss/markup/static/scss/mixins.scss ================================================ // Mixins. @mixin nl { margin: 0; padding: 0; text-indent: 0; list-style: none; list-style-position: outside; } @mixin cf { &:before, &:after { display: table; content: ""; } &:after { clear: both; } .lt-ie8 & { zoom: 1; } } @mixin blocks-justify { text-align: justify; text-justify: newspaper; } // You can add your own mixins here: ================================================ FILE: templates/scss/markup/static/scss/normalize.scss ================================================ /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document ========================================================================== */ /** * 1. Correct the line height in all browsers. * 2. Prevent adjustments of font size after orientation changes in iOS. */ html { line-height: 1.15; /* 1 */ -webkit-text-size-adjust: 100%; /* 2 */ } /* Sections ========================================================================== */ /** * Remove the margin in all browsers. */ body { margin: 0; } /** * Render the `main` element consistently in IE. */ main { display: block; } /** * Correct the font size and margin on `h1` elements within `section` and * `article` contexts in Chrome, Firefox, and Safari. */ h1 { font-size: 2em; margin: 0.67em 0; } /* Grouping content ========================================================================== */ /** * 1. Add the correct box sizing in Firefox. * 2. Show the overflow in Edge and IE. */ hr { box-sizing: content-box; /* 1 */ height: 0; /* 1 */ overflow: visible; /* 2 */ } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ pre { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /* Text-level semantics ========================================================================== */ /** * Remove the gray background on active links in IE 10. */ a { background-color: transparent; } /** * 1. Remove the bottom border in Chrome 57- * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. */ abbr[title] { border-bottom: none; /* 1 */ text-decoration: underline; /* 2 */ text-decoration: underline dotted; /* 2 */ } /** * Add the correct font weight in Chrome, Edge, and Safari. */ b, strong { font-weight: bolder; } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ code, kbd, samp { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /** * Add the correct font size in all browsers. */ small { font-size: 80%; } /** * Prevent `sub` and `sup` elements from affecting the line height in * all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.5em; } /* Embedded content ========================================================================== */ /** * Remove the border on images inside links in IE 10. */ img { border-style: none; } /* Forms ========================================================================== */ /** * 1. Change the font styles in all browsers. * 2. Remove the margin in Firefox and Safari. */ button, input, optgroup, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 1 */ line-height: 1.15; /* 1 */ margin: 0; /* 2 */ } /** * Show the overflow in IE. * 1. Show the overflow in Edge. */ button, input { /* 1 */ overflow: visible; } /** * Remove the inheritance of text transform in Edge, Firefox, and IE. * 1. Remove the inheritance of text transform in Firefox. */ button, select { /* 1 */ text-transform: none; } /** * Correct the inability to style clickable types in iOS and Safari. */ button, [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; } /** * Remove the inner border and padding in Firefox. */ button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; } /** * Restore the focus styles unset by the previous rule. */ button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; } /** * Correct the padding in Firefox. */ fieldset { padding: 0.35em 0.75em 0.625em; } /** * 1. Correct the text wrapping in Edge and IE. * 2. Correct the color inheritance from `fieldset` elements in IE. * 3. Remove the padding so developers are not caught out when they zero out * `fieldset` elements in all browsers. */ legend { box-sizing: border-box; /* 1 */ color: inherit; /* 2 */ display: table; /* 1 */ max-width: 100%; /* 1 */ padding: 0; /* 3 */ white-space: normal; /* 1 */ } /** * Add the correct vertical alignment in Chrome, Firefox, and Opera. */ progress { vertical-align: baseline; } /** * Remove the default vertical scrollbar in IE 10+. */ textarea { overflow: auto; } /** * 1. Add the correct box sizing in IE 10. * 2. Remove the padding in IE 10. */ [type="checkbox"], [type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** * Correct the cursor style of increment and decrement buttons in Chrome. */ [type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; } /** * 1. Correct the odd appearance in Chrome and Safari. * 2. Correct the outline style in Safari. */ [type="search"] { -webkit-appearance: textfield; /* 1 */ outline-offset: -2px; /* 2 */ } /** * Remove the inner padding in Chrome and Safari on macOS. */ [type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** * 1. Correct the inability to style clickable types in iOS and Safari. * 2. Change font properties to `inherit` in Safari. */ ::-webkit-file-upload-button { -webkit-appearance: button; /* 1 */ font: inherit; /* 2 */ } /* Interactive ========================================================================== */ /* * Add the correct display in Edge, IE 10+, and Firefox. */ details { display: block; } /* * Add the correct display in all browsers. */ summary { display: list-item; } /* Misc ========================================================================== */ /** * Add the correct display in IE 10+. */ template { display: none; } /** * Add the correct display in IE 10. */ [hidden] { display: none; } ================================================ FILE: templates/scss/markup/static/scss/plugins/sample-plugin.scss ================================================ // This is a sample file for scss for plugins // Each plugin's scss code have to be in separate files ================================================ FILE: templates/scss/markup/static/scss/separate-css/separate-css-sample.css ================================================ ================================================ FILE: templates/scss/markup/static/scss/sprite-generator-templates/scss.sprite.mustache ================================================ { // Default options 'functions': true } {{#items}} ${{name}}: {{px.x}} {{px.y}} {{px.offset_x}} {{px.offset_y}} {{px.width}} {{px.height}} {{px.total_width}} {{px.total_height}} '{{{escaped_image}}}'; {{/items}} {{#options.functions}} @mixin sprite-position($sprite) { $sprite-offset-x: nth($sprite, 3); $sprite-offset-y: nth($sprite, 4); background-position: $sprite-offset-x $sprite-offset-y; } @mixin sprite-image($sprite) { $sprite-image: nth($sprite, 9); background-image: url(%=static=%png-sprite/96dpi/#{$sprite-image}); } @mixin sprite-mixin-template($sprite) { @include sprite-image($sprite); @include sprite-position($sprite); width: nth($sprite, 5); height: nth($sprite, 6); } @mixin bg($sprite, $repeat: no-repeat) { @include sprite-mixin-template($sprite); $sprite-total-width: nth($sprite, 7); $sprite-total-height: nth($sprite, 8); background-size: $sprite-total-width, $sprite-total-height; background-repeat: $repeat; {{#options.dpi192}} @media screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min-resolution: 192dpi), only screen and ( min-resolution: 2dppx), only screen and (min-device-pixel-ratio: 2) { $sprite-image: nth($sprite, 9); background-image: url(%=static=%png-sprite/192dpi/#{$sprite-image}); } {{/options.dpi192}} {{#options.dpi288}} @media screen and (-webkit-min-device-pixel-ratio: 3), only screen and ( min-resolution: 288dpi), only screen and ( min-resolution: 3dppx), only screen and (min-device-pixel-ratio: 3) { $sprite-image: nth($sprite, 9); background-image: url(%=static=%png-sprite/288dpi/#{$sprite-image}); } {{/options.dpi288}} {{#options.dpi384}} @media screen and (-webkit-min-device-pixel-ratio: 4), only screen and ( min-resolution: 384dpi), only screen and ( min-resolution: 4dppx), only screen and (min-device-pixel-ratio: 4) { $sprite-image: nth($sprite, 9); background-image: url(%=static=%png-sprite/384dpi/#{$sprite-image}); } {{/options.dpi384}} } {{/options.functions}} ================================================ FILE: templates/scss/markup/static/scss/sprite-generator-templates/scss.svg-fallback-sprite.mustache ================================================ { // Default options 'functions': true } {{#items}} ${{name}}: {{px.x}} {{px.y}} {{px.offset_x}} {{px.offset_y}} {{px.width}} {{px.height}} {{px.total_width}} {{px.total_height}} '{{{escaped_image}}}' '{{{name}}}'; {{/items}} {{#options.functions}} @mixin svg-sprite-position($svg-sprite) { $svg-sprite-offset-x: nth($svg-sprite, 3); $svg-sprite-offset-y: nth($svg-sprite, 4); background-position: $svg-sprite-offset-x $svg-sprite-offset-y; } @mixin svg-sprite-image($svg-sprite) { $svg-sprite-image: nth($svg-sprite, 9); background-image: url(%=static=%rastered-svg-sprite/#{$svg-sprite-image}); } @mixin bg-svg($svg-sprite, $repeat: no-repeat) { @include svg-sprite-image($svg-sprite); @include svg-sprite-position($svg-sprite); width: nth($svg-sprite, 5); height: nth($svg-sprite, 6); background-repeat: $repeat; } {{/options.functions}} ================================================ FILE: templates/scss/markup/static/scss/sprite-generator-templates/scss.svg-sprite.mustache ================================================ {{#sprites}} ${{fileName}}: {{x}}{{units}} {{y}}{{units}} {{w}}{{units}} {{h}}{{units}} {{width}}{{units}} {{height}}{{units}} '{{{cssPathSvg}}}' '{{{fileName}}}'; {{/sprites}} @mixin svg-sprite-position($svg-sprite) { $svg-sprite-offset-x: nth($svg-sprite, 1); $svg-sprite-offset-y: nth($svg-sprite, 2); background-position: $svg-sprite-offset-x $svg-sprite-offset-y; } @mixin bg-svg($svg-sprite, $repeat: no-repeat) { background-image: url('%=static=%svg-sprite/{{imgName}}'); @include svg-sprite-position($svg-sprite); width: nth($svg-sprite, 3); height: nth($svg-sprite, 4); background-repeat: $repeat; } ================================================ FILE: templates/scss/markup/static/scss/sprites-scss/sprite-ie.scss ================================================ @mixin bg($sprite, $repeat: no-repeat) { @include sprite-mixin-template($sprite); background-repeat: $repeat; } ================================================ FILE: templates/scss/markup/static/scss/vars.scss ================================================ // File for scss-vars. // For example: main colors, paddings and so on. ================================================ FILE: templates/stylus/markup/components/_template/_template.styl ================================================ ================================================ FILE: templates/stylus/markup/static/stylus/GUI.styl ================================================ // GUI stylies of the project // For example, styles of the links, buttons and so on. ================================================ FILE: templates/stylus/markup/static/stylus/common.styl ================================================ // Common styles of the project html, body height 100% .page // Стили для body .page__wrapper min-height 100% margin-bottom -50px * html .page__wrapper height 100% .page__buffer height 50px ================================================ FILE: templates/stylus/markup/static/stylus/entry/built-in-partials/_service-ie8.styl ================================================ /* Some styles, which is used for correct sprite-generation, vars, mixins and etc */ /* Please, do not edit with file! */ /* This file can be overwritten by update-project! */ /* Mixins, which are specific for current project */ @import '../../mixins.styl'; /* Mixins and vars for sprite generation */ @import '../../sprites-stylus/sprite_96.styl'; @import '../../sprites-stylus/sprite-png.styl'; @import '../../sprites-stylus/svg-fallback-sprite.styl'; @import '../../sprites-stylus/sprite-png-ie.styl'; /* Stylus for used fonts */ @import '../../fonts.styl'; /* Vars, which are specific for current project */ @import '../../vars.styl'; /* Styles for UI-elements */ @import '../../GUI.styl'; /* Common styles for current project */ @import '../../common.styl'; ================================================ FILE: templates/stylus/markup/static/stylus/entry/built-in-partials/_service.styl ================================================ /* Some styles, which is used for correct sprite-generation, vars, mixins and etc */ /* Please, do not edit with file! */ /* This file can be overwritten by update-project! */ /* Mixins, which are specific for current project */ @import '../../mixins.styl'; /* Mixins and vars for sprite generation */ @import '../../sprites-stylus/sprite_96.styl'; @import '../../sprites-stylus/sprite-png.styl'; @import '../../sprites-stylus/svg-sprite.styl'; /* Stylus for used fonts */ @import '../../fonts.styl'; /* Vars, which are specific for current project */ @import '../../vars.styl'; /* Styles for UI-elements */ @import '../../GUI.styl'; /* Common styles for current project */ @import '../../common.styl'; ================================================ FILE: templates/stylus/markup/static/stylus/entry/ie/main_ie8.styl ================================================ @import '../../normalize.styl'; /* Libraries, which is used in current project. */ @import '../partials/_libraries.styl'; /* Libraries, which is used in current project. */ @import '../built-in-partials/_service-ie8.styl'; /* Plugins, which is used in current project. */ @import '../partials/_plugins.styl'; /* Components, which is used in current project. */ @import '../partials/_components.styl'; @import '../partials/_components-ie8.styl'; /* Additional style files. */ @import '../../etc/etc.styl'; ================================================ FILE: templates/stylus/markup/static/stylus/entry/ie/main_ie9.styl ================================================ @import '../../normalize.styl'; /* Libraries, which is used in current project. */ @import '../partials/_libraries.styl'; /* Libraries, which is used in current project. */ @import '../built-in-partials/_service.styl'; /* Plugins, which is used in current project. */ @import '../partials/_plugins.styl'; /* Components, which is used in current project. */ @import '../partials/_components.styl'; @import '../partials/_components-ie9.styl'; /* Additional style files. */ @import '../../etc/etc.styl'; ================================================ FILE: templates/stylus/markup/static/stylus/entry/main.styl ================================================ @import '../normalize.styl'; /* Libraries, which is used in current project. */ @import 'partials/_libraries.styl'; /* Libraries, which is used in current project. */ @import 'built-in-partials/_service.styl'; /* Plugins, which is used in current project. */ @import 'partials/_plugins.styl'; /* Components, which is used in current project. */ @import 'partials/_components.styl'; /* Additional style files. */ @import '../etc/etc.styl'; ================================================ FILE: templates/stylus/markup/static/stylus/entry/partials/_components-ie8.styl ================================================ ================================================ FILE: templates/stylus/markup/static/stylus/entry/partials/_components-ie9.styl ================================================ ================================================ FILE: templates/stylus/markup/static/stylus/entry/partials/_components.styl ================================================ // @import 'components/_template/_template.styl'; ================================================ FILE: templates/stylus/markup/static/stylus/entry/partials/_libraries.styl ================================================ ================================================ FILE: templates/stylus/markup/static/stylus/entry/partials/_plugins.styl ================================================ ================================================ FILE: templates/stylus/markup/static/stylus/etc/etc.styl ================================================ ================================================ FILE: templates/stylus/markup/static/stylus/fonts.styl ================================================ /* Your custom fonts here */ /* Example @font-face { font-family: 'CustomFont'; src: url('../fonts/Custom-Font.eot'); src: url('../fonts/Custom-Font.eot?#iefix') format('embedded-opentype'), url('../fonts/Custom-Font.woff') format('woff'), url('../fonts/Custom-Font.svg#custom_font') format('svg'); font-weight: 400; // For normal width. It could has another value font-style: normal; // Also could has another value } // Var for using custom font $CustomFont: 'CustomFont', Helvetica, Arial, sans-serif; */ ================================================ FILE: templates/stylus/markup/static/stylus/libraries/library-sample.styl ================================================ ================================================ FILE: templates/stylus/markup/static/stylus/mixins.styl ================================================ // Mixins. m-nl() margin 0 padding 0 text-indent 0 list-style none list-style-position outside m-cf() &:before, &:after display table content "" &:after clear both .lt-ie8 & zoom 1 m-blocks-justify() text-align justify text-justify newspaper // You can add your own mixins here: ================================================ FILE: templates/stylus/markup/static/stylus/normalize.styl ================================================ /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document ========================================================================== */ /** * 1. Correct the line height in all browsers. * 2. Prevent adjustments of font size after orientation changes in iOS. */ html { line-height: 1.15; /* 1 */ -webkit-text-size-adjust: 100%; /* 2 */ } /* Sections ========================================================================== */ /** * Remove the margin in all browsers. */ body { margin: 0; } /** * Render the `main` element consistently in IE. */ main { display: block; } /** * Correct the font size and margin on `h1` elements within `section` and * `article` contexts in Chrome, Firefox, and Safari. */ h1 { font-size: 2em; margin: 0.67em 0; } /* Grouping content ========================================================================== */ /** * 1. Add the correct box sizing in Firefox. * 2. Show the overflow in Edge and IE. */ hr { box-sizing: content-box; /* 1 */ height: 0; /* 1 */ overflow: visible; /* 2 */ } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ pre { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /* Text-level semantics ========================================================================== */ /** * Remove the gray background on active links in IE 10. */ a { background-color: transparent; } /** * 1. Remove the bottom border in Chrome 57- * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. */ abbr[title] { border-bottom: none; /* 1 */ text-decoration: underline; /* 2 */ text-decoration: underline dotted; /* 2 */ } /** * Add the correct font weight in Chrome, Edge, and Safari. */ b, strong { font-weight: bolder; } /** * 1. Correct the inheritance and scaling of font size in all browsers. * 2. Correct the odd `em` font sizing in all browsers. */ code, kbd, samp { font-family: monospace, monospace; /* 1 */ font-size: 1em; /* 2 */ } /** * Add the correct font size in all browsers. */ small { font-size: 80%; } /** * Prevent `sub` and `sup` elements from affecting the line height in * all browsers. */ sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } sub { bottom: -0.25em; } sup { top: -0.5em; } /* Embedded content ========================================================================== */ /** * Remove the border on images inside links in IE 10. */ img { border-style: none; } /* Forms ========================================================================== */ /** * 1. Change the font styles in all browsers. * 2. Remove the margin in Firefox and Safari. */ button, input, optgroup, select, textarea { font-family: inherit; /* 1 */ font-size: 100%; /* 1 */ line-height: 1.15; /* 1 */ margin: 0; /* 2 */ } /** * Show the overflow in IE. * 1. Show the overflow in Edge. */ button, input { /* 1 */ overflow: visible; } /** * Remove the inheritance of text transform in Edge, Firefox, and IE. * 1. Remove the inheritance of text transform in Firefox. */ button, select { /* 1 */ text-transform: none; } /** * Correct the inability to style clickable types in iOS and Safari. */ button, [type="button"], [type="reset"], [type="submit"] { -webkit-appearance: button; } /** * Remove the inner border and padding in Firefox. */ button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner { border-style: none; padding: 0; } /** * Restore the focus styles unset by the previous rule. */ button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring { outline: 1px dotted ButtonText; } /** * Correct the padding in Firefox. */ fieldset { padding: 0.35em 0.75em 0.625em; } /** * 1. Correct the text wrapping in Edge and IE. * 2. Correct the color inheritance from `fieldset` elements in IE. * 3. Remove the padding so developers are not caught out when they zero out * `fieldset` elements in all browsers. */ legend { box-sizing: border-box; /* 1 */ color: inherit; /* 2 */ display: table; /* 1 */ max-width: 100%; /* 1 */ padding: 0; /* 3 */ white-space: normal; /* 1 */ } /** * Add the correct vertical alignment in Chrome, Firefox, and Opera. */ progress { vertical-align: baseline; } /** * Remove the default vertical scrollbar in IE 10+. */ textarea { overflow: auto; } /** * 1. Add the correct box sizing in IE 10. * 2. Remove the padding in IE 10. */ [type="checkbox"], [type="radio"] { box-sizing: border-box; /* 1 */ padding: 0; /* 2 */ } /** * Correct the cursor style of increment and decrement buttons in Chrome. */ [type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button { height: auto; } /** * 1. Correct the odd appearance in Chrome and Safari. * 2. Correct the outline style in Safari. */ [type="search"] { -webkit-appearance: textfield; /* 1 */ outline-offset: -2px; /* 2 */ } /** * Remove the inner padding in Chrome and Safari on macOS. */ [type="search"]::-webkit-search-decoration { -webkit-appearance: none; } /** * 1. Correct the inability to style clickable types in iOS and Safari. * 2. Change font properties to `inherit` in Safari. */ ::-webkit-file-upload-button { -webkit-appearance: button; /* 1 */ font: inherit; /* 2 */ } /* Interactive ========================================================================== */ /* * Add the correct display in Edge, IE 10+, and Firefox. */ details { display: block; } /* * Add the correct display in all browsers. */ summary { display: list-item; } /* Misc ========================================================================== */ /** * Add the correct display in IE 10+. */ template { display: none; } /** * Add the correct display in IE 10. */ [hidden] { display: none; } ================================================ FILE: templates/stylus/markup/static/stylus/plugins/sample-plugin.styl ================================================ ================================================ FILE: templates/stylus/markup/static/stylus/separate-css/separate-css-sample.css ================================================ ================================================ FILE: templates/stylus/markup/static/stylus/sprite-generator-templates/stylus.sprite.mustache ================================================ { // Default options 'functions': true } {{#items}} ${{name}} = {{px.x}} {{px.y}} {{px.offset_x}} {{px.offset_y}} {{px.width}} {{px.height}} {{px.total_width}} {{px.total_height}} '{{{escaped_image}}}' '{{{name}}}'; {{/items}} {{#options.functions}} bg-template($sprite, $repeat = no-repeat) { width: $sprite[4]; height: $sprite[5]; background-position: $sprite[2] $sprite[3]; background-image: url('%=static=%png-sprite/96dpi/' + $sprite[8]); background-size: $sprite[6] $sprite[7]; background-repeat: $repeat; } highDpiMedia($sprite) { {{#options.dpi192}} @media screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min-resolution: 192dpi), only screen and ( min-resolution: 2dppx), only screen and (min-device-pixel-ratio: 2) { background-image: url('%=static=%png-sprite/192dpi/' + $sprite[8]); } {{/options.dpi192}} {{#options.dpi288}} @media screen and (-webkit-min-device-pixel-ratio: 3), only screen and ( min-resolution: 288dpi), only screen and ( min-resolution: 3dppx), only screen and (min-device-pixel-ratio: 3) { background-image: url('%=static=%png-sprite/288dpi/' + $sprite[8]); } {{/options.dpi288}} {{#options.dpi384}} @media screen and (-webkit-min-device-pixel-ratio: 4), only screen and ( min-resolution: 384dpi), only screen and ( min-resolution: 4dppx), only screen and (min-device-pixel-ratio: 4) { background-image: url('%=static=%png-sprite/384dpi/' + $sprite[8]); } {{/options.dpi384}} } {{/options.functions}} ================================================ FILE: templates/stylus/markup/static/stylus/sprite-generator-templates/stylus.svg-fallback-sprite.mustache ================================================ { // Default options 'functions': true } {{#items}} ${{name}} = {{px.x}} {{px.y}} {{px.offset_x}} {{px.offset_y}} {{px.width}} {{px.height}} {{px.total_width}} {{px.total_height}} '{{{escaped_image}}}' '{{{name}}}'; {{/items}} {{#options.functions}} svg-sprite-position($svg-sprite) { $svg-sprite-offset-x = $svg-sprite[2]; $svg-sprite-offset-y = $svg-sprite[3]; background-position: $svg-sprite-offset-x $svg-sprite-offset-y; } svg-sprite-image($svg-sprite) { background-image: url('%=static=%rastered-svg-sprite/' + $svg-sprite[8]); } bg-svg($svg-sprite, $repeat = no-repeat) { svg-sprite-image($svg-sprite); svg-sprite-position($svg-sprite); width: $svg-sprite[4]; height: $svg-sprite[5]; background-repeat: $repeat; } {{/options.functions}} ================================================ FILE: templates/stylus/markup/static/stylus/sprite-generator-templates/stylus.svg-sprite.mustache ================================================ {{#sprites}} ${{fileName}} = {{x}}{{units}} {{y}}{{units}} {{w}}{{units}} {{h}}{{units}} {{width}}{{units}} {{height}}{{units}} '{{{cssPathSvg}}}' '{{{fileName}}}'; {{/sprites}} svg-sprite-position($svg-sprite) { $svg-sprite-offset-x = $svg-sprite[0]; $svg-sprite-offset-y = $svg-sprite[1]; background-position: $svg-sprite-offset-x $svg-sprite-offset-y; } bg-svg($svg-sprite, $repeat = no-repeat) { background-image: url('%=static=%svg-sprite/{{imgName}}'); svg-sprite-position($svg-sprite); width: $svg-sprite[2]; height: $svg-sprite[3]; background-repeat: $repeat; } ================================================ FILE: templates/stylus/markup/static/stylus/sprites-stylus/sprite-png-ie.styl ================================================ bg($sprite, $repeat = no-repeat) { bg-template($sprite, $repeat = no-repeat); } ================================================ FILE: templates/stylus/markup/static/stylus/sprites-stylus/sprite-png.styl ================================================ bg($sprite, $repeat = no-repeat) { bg-template($sprite, $repeat = no-repeat); highDpiMedia($sprite); } ================================================ FILE: templates/stylus/markup/static/stylus/vars.styl ================================================ // File for less-vars. // For example: main colors, paddings and so on. ================================================ FILE: user-package.json ================================================ { "dependencies": { } } ================================================ FILE: webpack.config.js ================================================ 'use strict'; const path = require('path'); const cwd = process.cwd(); const webpack = tars.require('webpack'); const TerserJsPlugin = tars.require('terser-webpack-plugin'); const staticFolderName = tars.config.fs.staticFolderName; const compressJs = tars.flags.release || tars.flags.min || tars.flags.m; const generateSourceMaps = tars.config.sourcemaps.js.active && tars.isDevMode; const sourceMapsDest = tars.config.sourcemaps.js.inline ? 'inline-' : ''; const sourceMapsType = `#${sourceMapsDest}source-map`; const webpackMode = !compressJs ? 'development' : 'production'; let outputFileNameTemplate = '[name]'; let modulesDirectories = ['node_modules']; let rules = [ { test: /\.js$/, loader: 'source-map-loader', enforce: 'pre' } ]; let plugins = [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV) } }) ]; let minimizers = []; if (process.env.npmRoot) { modulesDirectories.push(process.env.npmRoot); } if (compressJs) { outputFileNameTemplate += `${tars.options.build.hash}.min`; minimizers.push( new TerserJsPlugin({ terserOptions: { compress: { /* eslint-disable camelcase */ drop_console: tars.config.js.removeConsoleLog, drop_debugger: tars.config.js.removeConsoleLog /* eslint-enable camelcase */ }, mangle: false } }) ); } if (tars.config.js.webpack.providePlugin) { plugins.push( new webpack.ProvidePlugin(tars.config.js.webpack.providePlugin) ); } if (tars.options.watch.isActive && tars.config.js.webpack.useHMR) { plugins.push( new webpack.HotModuleReplacementPlugin() ); } if (tars.config.js.lint) { rules.push( { test: /\.js$/, loader: 'eslint-loader', enforce: 'pre', include: `${cwd}/markup`, options: { configFile: `${cwd}/.eslintrc` } } ); } if (tars.config.js.useBabel) { rules.push( { test: /\.js$/, loader: 'babel-loader', include: /markup/ } ); } /** * Add to each entry point entries for webpack dev-server and webpack-hot-middleware * @param {Object} entryConfig * @return {Object} */ function prepareEntryPoints(entryConfig) { const useHMR = tars.config.js.webpack.useHMR; let devServerEntryPoints = [ 'webpack/hot/dev-server', 'webpack-hot-middleware/client?reload=true' ]; if (!useHMR || !tars.useLiveReload) { return entryConfig; } // Take webpack dev-server and webpack-hot-middleware from TARS-CLI, if TARS has been started by TARS-CLI if (process.env.npmRoot) { devServerEntryPoints = devServerEntryPoints.map(devServerEntryPoint => process.env.npmRoot + devServerEntryPoint); } /* eslint-disable guard-for-in */ for (let entryPointName in entryConfig) { entryConfig[entryPointName] = devServerEntryPoints.concat(entryConfig[entryPointName]); } /* eslint-disable guard-for-in */ return entryConfig; } module.exports = { mode: webpackMode, // We have to add some pathes to entry point in case of using HMR entry: prepareEntryPoints({ main: path.resolve(`${cwd}/markup/${staticFolderName}/js/main.js`) }), output: { path: path.resolve(`${(tars.isDevMode) ? `${tars.config.devPath}` : `${tars.options.build.path}`}/${staticFolderName}/js`), publicPath: `./${staticFolderName}/js/`, filename: `${outputFileNameTemplate}.js` }, devtool: generateSourceMaps ? sourceMapsType : false, watch: tars.options.watch.isActive && !tars.config.js.webpack.useHMR, module: { rules }, plugins, resolveLoader: { modules: modulesDirectories }, optimization: { minimizer: minimizers }, resolve: { alias: { modules: path.resolve(`./markup/${tars.config.fs.componentsFolderName}`), components: path.resolve(`./markup/${tars.config.fs.componentsFolderName}`), static: path.resolve(`./markup/${staticFolderName}`) } } };