autofront 2.2.3 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +55 -81
  2. package/index.js +426 -118
  3. package/package.json +40 -48
package/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # Autofront
2
2
 
3
- Automatisation of front-end by [Gulp](https://gulpjs.com) and [Bower](https://bower.io).
3
+ Automation of front-end by [Gulp](https://gulpjs.com) and [Bower](https://bower.io).
4
4
 
5
5
  ## Get started
6
6
 
7
7
  ### Gulp
8
8
 
9
- Install its CLI, following [the official manual](https://gulpjs.com/docs/en/getting-started/quick-start/) but skipping [the local package](https://gulpjs.com/docs/en/getting-started/quick-start/#install-the-gulp-package-in-your-devdependencies) and the next steps.
9
+ Install its CLI (following [the official manual](https://gulpjs.com/docs/en/getting-started/quick-start/) but skipping [the local package](https://gulpjs.com/docs/en/getting-started/quick-start/#install-the-gulp-package-in-your-devdependencies) and the next steps).
10
10
 
11
11
  And put `gulpfile.js` simply with:
12
12
 
@@ -18,112 +18,86 @@ require('autofront');
18
18
 
19
19
  [Install it](https://bower.io/#install-bower), [initialize it and save dependencies](https://bower.io/#save-packages).
20
20
 
21
- ### Install
21
+ ### Installation
22
22
 
23
23
  ```sh
24
24
  npm install --save-dev autofront
25
25
  ```
26
26
 
27
- ### Main page
28
-
29
- In `src` directory, place `index.html` whose content would have to look basically like:
30
-
31
- ```html
32
- <!DOCTYPE html>
33
- <html>
34
- <head>
35
- <!-- build:css styles/vendor.css -->
36
- <!-- bower:css --><!-- endbower -->
37
- <!-- endbuild -->
38
- </head>
39
- <body>
40
- <!-- build:js scripts/vendor.js -->
41
- <!-- bower:js --><!-- endbower -->
42
- <!-- endbuild -->
43
- <!-- build:js scripts/app.js -->
44
- <!-- inject:js -->
45
- <!-- endinject -->
46
- <!-- endbuild -->
47
- </body>
48
- </html>
49
- ```
27
+ ### Source code
28
+
29
+ Place inside directory `src`; at least including the main page (`index.html`), without embedding tags (`<link>`s and `<script>`s).
50
30
 
51
31
  ### Run
52
32
 
53
- Finally initiate your project development:
33
+ Finally, initiate the project, commanding:
54
34
 
55
35
  ```sh
56
36
  gulp
57
37
  ```
58
38
 
59
- A browser tab will be opened. Then, try editing the HTML to view the web refresh.
39
+ A browser tab is opened. Now you are ready to develop!
60
40
 
61
- Other command options, that appear immediately below, are available. And to use another programming languages, see [the proper section](#support).
41
+ To reach further, see below.
62
42
 
63
43
  ## Usage
64
44
 
65
45
  ### Tasks
66
46
 
67
- The Gulp ones are the following:
68
-
69
- - `gulp` or `gulp serve` are for running a test server and develop with live reload.
70
- - `gulp build` only builds production code, the distributable application (`dist` folder).
71
- - With `gulp serve:dist`, a combination of the above is achieved: Specifically, the server runs that last version but without reload.
72
-
73
- ### Domains
74
-
75
- On executing Gulp command, an additional parameter can be included (e.g.: `gulp --dev` or `gulp build --pro`) to indicate the domain of connection path. Defaults to `--local`.
76
-
77
- These domain URLs would be searched in `package.json` listed in the property `domains` (optionally also `domainAliases`, to assign domain name for each alias).
78
-
79
- And, to capture the selected URL string, put `{{AUTOFRONT_DOMAIN}}` where it would be located in your source code.
80
-
81
- ## Support
82
-
83
- Positioning in source folder (`src`), you can utilize:
84
-
85
- ### HTML
86
-
87
- Besides of required `index.html`, it is possible to add more files. In this case, they will be treated as [templates](https://docs.angularjs.org/api/ng/directive/ngInclude) and, to work properly with `dist`, AngularJS must to be [appropriately](#angularjs) on.
47
+ The Gulp ones are:
88
48
 
89
- #### [Pug](https://pugjs.org)
49
+ | Name | Details | Processes |
50
+ | --- | --- | --- |
51
+ | `serve` (default) | Source code runs in a server with live reload. | <ul><li>Bower entry-point files catching.</li><li>Notification and injection of [environment](#environment-variables).</li><li>Compilation (Less, SCSS and Pug)[^1].</li><li>Set up[^2] of HTML5 mode.[^1]</li><li>Insertion of file with app info (`about.json`).</li></ul> |
52
+ | `build` | Production code is built (in folder `dist`). | The above and: <ul><li>Templates caching.[^1]</li><li>Concatenation to one hashed file (CSS and JS).</li><li>Minification (HTML, CSS, JS, images and JSON).</li><li>Console display of files size.</li></ul> |
53
+ | `serve:dist` | This distributable application is served but without the refreshing. | The same with the folder hidden. |
90
54
 
91
- Turn any hypertext file into Pug's one, except the mentioned untouchable index page.
55
+ [^1]: [If it is on](#settings).
56
+ [^2]: Invocation of [`$locationProvider`](https://docs.angularjs.org/api/ng/provider/$locationProvider#html5Mode) and a `<base>` injected.
92
57
 
93
- ### CSS
58
+ ### Environment variables
94
59
 
95
- Collocated in `styles` directory, type over lonely `index.css`.
60
+ They can be used in this way:
96
61
 
97
- #### [Less](https://lesscss.org)
62
+ 1. Define them. Look at [the next section](#settings).
63
+ 2. Put `AUTOFRONT_ENV` in your JS source code where it would be injected.
64
+ 3. On executing Gulp command, indicate the name of the current one to the flag argument `env`. Defaults to "development" with server tasks and to "production" with `build`.
98
65
 
99
- The same as before (but with its own file extension). The rest of optional files will be ignored if they are not [imported](https://lesscss.org/features/#import-atrules-feature).
66
+ ## Settings
100
67
 
101
- #### [Sass](https://sass-lang.com)
102
-
103
- Idem, but it is also obligatory an extra jointly: `_variables.scss`.
104
-
105
- ### JavaScript
106
-
107
- Wherever you want.
108
-
109
- #### [AngularJS](https://angularjs.org)
110
-
111
- One of modules should to be named "app", ideally the main one.
112
-
113
- Optionally, to work with [HTML5 mode](https://docs.angularjs.org/api/ng/provider/$locationProvider#html5Mode), invoke it:
68
+ You can configure it typing into Gulp file like this:
114
69
 
115
70
  ```js
116
- let autofront = require('autofront');
117
- autofront.html5Mode();
71
+ const autofront = require('autofront');
72
+
73
+ autofront.property = {
74
+ subproperty: value,
75
+ subproperty2: {
76
+ subproperty3: value2,
77
+ // ...
78
+ },
79
+ // ...
80
+ };
81
+ autofront.property2.subproperty4 = value3;
82
+ // ...
118
83
  ```
119
84
 
120
- ### Others
121
-
122
- Any asset (e.g. a PDF document) will keep the location path and, particularly at production, will take place an images optimization.
123
-
124
- ## Pending
125
-
126
- Improvements to do:
127
-
128
- - Replace Bower as dependency manager.
129
- - Migrate AngularJS to new [Angular](https://angular.io).
85
+ Defining with:
86
+
87
+ | Property | Subprop. | | Type | Details | Default |
88
+ | --- | --- | --- | --- | --- | --- |
89
+ | `html` | `pug` | | Boolean | [Pug](https://pugjs.org) activated? | `false` |
90
+ | `css` | `folder` | | String | Directory that contains CSS files. | `'styles/'` |
91
+ | <!-- 〃 --> | `filename` | | String | Filename of root files. | `'index'` |
92
+ | <!-- 〃 --> | `order` | | Number | Index of order to include content in stylesheet. | `0` |
93
+ | <!-- --> | `less`[^3] | `order` | Number | Idem for [Less](https://lesscss.org). | `1` |
94
+ | <!-- --> | `scss`[^3] | `order` | Number | Idem for [SCSS (Sass)](https://sass-lang.com/documentation/syntax#scss). | `2` |
95
+ | <!-- 〃 --> | <!-- 〃 --> | `variables` | String | Filename of variables file. | `_variables` |
96
+ | <!-- 〃 --> | `fonts` | `folder` | String | Location (folder path) of font files from Bower. | `'fonts/'` |
97
+ | <!-- 〃 --> | <!-- 〃 --> | `extensions` | String or array of strings | File extensions to catch. | `['eot', 'otf', 'svg', 'ttf', 'woff', 'woff2']` |
98
+ | `js` | `ng`[^3] | `module` | String | Name of [AngularJS](https://angularjs.org) main module. | `'app'` |
99
+ | <!-- 〃 --> | <!-- 〃 --> | `html5Mode` | Boolean | [HTML5 mode](https://docs.angularjs.org/guide/$location#html5-mode) enabled? | `false` |
100
+ | <!-- 〃 --> | <!-- 〃 --> | `template` | Boolean | Templates loaded by [`$templateCache`](https://docs.angularjs.org/api/ng/service/$templateCache)? | `true` |
101
+ | <!-- 〃 --> | `envs` | | Object | Environment variables list, with names as keys and data (whatever can be JSON parsed) as values. | `{}` |
102
+
103
+ [^3]: It can be disabled assigning a falsy value.
package/index.js CHANGED
@@ -1,123 +1,254 @@
1
- this.html5Mode = html5Mode;
1
+ const defSettings = {
2
+ html: { pug: false },
3
+ css: {
4
+ folder: 'styles/',
5
+ filename: 'index',
6
+ order: 0,
7
+ less: { order: 1 },
8
+ scss: {
9
+ order: 2,
10
+ variables: '_variables'
11
+ },
12
+ fonts: {
13
+ folder: 'fonts/',
14
+ extensions: ['eot', 'otf', 'svg', 'ttf', 'woff', 'woff2']
15
+ }
16
+ },
17
+ js: {
18
+ ng: {
19
+ module: 'app',
20
+ html5Mode: false,
21
+ template: true
22
+ },
23
+ envs: {}
24
+ }
25
+ };
26
+ const settings = this;
27
+ for (const name in defSettings)
28
+ settings[name] = { ...defSettings[name] };
2
29
 
3
30
  const gulp = require('gulp'),
4
- path = require('path'),
5
- args = require('get-gulp-args')(),
6
- mergeStream = require('merge-stream'),
7
- mainBowerFiles = require('main-bower-files'),
8
31
  $ = require('gulp-load-plugins')(),
9
- injStr = $.injectString,
10
- gulpSass = $.sass(require('sass')),
11
32
  notifyError = $.notify.onError(error => error.message),
33
+ gulpFilter = ext => $.filter(getGlob(ext), { restore: true }),
12
34
  browserSync = require('browser-sync').create(),
13
- deleteEmpty = require('delete-empty');
35
+ deleteEmpty = require('delete-empty'),
36
+ gulpHtmlmin = () => $.htmlmin({ collapseWhitespace: true, conservativeCollapse: true }),
37
+ fs = require('fs'),
38
+ hidefile = require('hidefile');
14
39
 
15
- let domain = undefined;
40
+ let defEnv = 'production',
41
+ envName,
42
+ envValue;
16
43
 
17
44
  const allFiles = getGlob(),
18
- indexHtmlFile = 'index.html',
45
+ indexFile = 'index.html',
46
+ scriptsDir = 'scripts/',
19
47
  jsFiles = getGlob('js'),
20
- cssFilename = 'index',
21
- cssFile = cssFilename + '.css';
22
- let stylesDir = 'styles/',
23
- jsTemplatesFile = 'scripts/templates.js';
48
+ cssComment = '<!-- autofrontcss -->',
49
+ endCssComment = '<!-- endautofrontcss -->',
50
+ jsComment = '<!-- autofrontjs -->',
51
+ html5ModeJsFile = scriptsDir + 'html5-mode.js',
52
+ jsTemplatesFile = scriptsDir + 'templates.js',
53
+ endJsComment = '<!-- endautofrontjs -->',
54
+ cssFile = 'index.css',
55
+ jsFile = 'index.js';
56
+ let stylesDir,
57
+ stylesFilename,
58
+ cssExtensions = [];
24
59
 
25
60
  const globs = {
26
61
  src: 'src/',
27
62
  tmp: '.tmp/',
28
63
  dist: 'dist/'
29
64
  };
30
- globs.srcIndexHtml = globs.src + indexHtmlFile;
65
+ globs.hiddenDist = '.' + globs.dist;
66
+ globs.srcIndex = globs.src + indexFile;
31
67
  globs.srcJs = globs.src + jsFiles;
32
- globs.srcIndexAndSrcJs = [globs.srcIndexHtml, globs.srcJs];
33
- globs.srcStyles = [globs.src + stylesDir + cssFile, globs.src + getGlob('less'), globs.src + getGlob('scss')];
34
- globs.srcOthers = [globs.src + allFiles, ...[...globs.srcIndexAndSrcJs, ...globs.srcStyles].map(glob => '!' + glob)];
68
+ globs.srcOthers = [globs.src + allFiles];
35
69
  globs.tmpAllFiles = globs.tmp + allFiles;
70
+ globs.distIndexFile = globs.dist + indexFile;
71
+ globs.distTmpls = [globs.dist + getGlob('html'), '!' + globs.distIndexFile];
36
72
 
37
- const nl = '\n',
73
+ const nl = '\r\n',
38
74
  tab = ' ';
39
75
 
40
- function clean() {
41
- return delDir(globs.tmp);
76
+ function setDefaultEnv(cb) {
77
+ defEnv = 'development';
78
+ cb();
42
79
  }
43
-
44
- function manageDomain() {
45
- const pckg = require(path.resolve('package.json')),
46
- domains = pckg.domains;
47
- let domainIndex = args[0] || 'local';
48
- if (domains) {
49
- const domainAliases = pckg.domainAliases;
50
- if (domainAliases) {
51
- const alias = domainAliases[domainIndex];
52
- if (alias)
53
- domainIndex = alias;
80
+ setDefaultEnv.displayName = 'set-default-env';
81
+
82
+ function setVariables(cb) {
83
+ stylesDir = getSetting('cssFolder');
84
+ stylesFilename = getSetting('filename');
85
+
86
+ for (const cssExt of [
87
+ {
88
+ name: 'css',
89
+ process: $.cssimport
90
+ },
91
+ {
92
+ name: 'less',
93
+ process: $.less,
94
+ isPreprocessor: true
95
+ },
96
+ {
97
+ name: 'scss',
98
+ process: $.sass(require('sass')),
99
+ getExtraCode: () => {
100
+ const file = globs.src + stylesDir + getSetting('variables') + '.scss';
101
+ return fileExists(file) ? `@import "${file}";` : '';
102
+ },
103
+ isPreprocessor: true
54
104
  }
55
- domain = domains[domainIndex];
105
+ ]) {
106
+ const name = cssExt.name;
107
+ if (!cssExt.isPreprocessor || getSetting(name))
108
+ cssExtensions.push({ getExtraCode: () => '', ...cssExt, order: getSetting(name + 'Order') });
109
+ }
110
+ cssExtensions = cssExtensions.sort((a, b) => a.order - b.order);
111
+
112
+ const srcStyles = [];
113
+ for (const cssExt of cssExtensions) {
114
+ const glob = globs.src + getGlob(cssExt.name);
115
+ srcStyles.push(glob);
116
+ cssExt.glob = glob;
56
117
  }
57
- const isMatched = domain !== undefined;
118
+ globs.srcOthers.push(...[globs.srcIndex, globs.srcJs, ...srcStyles].map(glob => '!' + glob));
119
+
120
+ cb();
121
+ }
122
+ setVariables.displayName = 'set-variables';
123
+
124
+ function getEnv() {
125
+ envName = require('get-gulp-args')().env || defEnv;
126
+ envValue = getSetting('envs')[envName];
127
+ const isMatched = envValue !== undefined;
58
128
  return gulp.src(globs.src, { read: false })
59
- .pipe($.notify(isMatched ? `Matching domain: "${domainIndex}".` : 'No domain matched.'));
129
+ .pipe($.notify(isMatched ? `Matching environment: "${envName}".` : 'No environment matched.'));
130
+ }
131
+ getEnv.displayName = 'get-env';
132
+
133
+ function removeFolder() {
134
+ return delDir(globs.tmp);
60
135
  }
61
- manageDomain.displayName = 'manage-domain';
136
+ removeFolder.displayName = 'remove-folder';
62
137
 
63
- function buildIndex() {
64
- return gulp.src(globs.srcIndexHtml)
65
- .pipe(injStr.after('<!-- endbuild -->', nl + tab + `<link rel="stylesheet" href="${stylesDir + cssFile}">`))
66
- .pipe($.inject(gulp.src(globs.srcJs).pipe($.angularFilesort()), { relative: true })).on('error', notifyError)
138
+ function createFolder() {
139
+ return gulp.src('*.*', { read: false })
140
+ .pipe(gulp.dest(globs.tmp));
141
+ }
142
+ createFolder.displayName = 'create-folder';
143
+
144
+ function hideFolder(cb) {
145
+ hideDir(globs.tmp);
146
+ cb();
147
+ }
148
+ hideFolder.displayName = 'hide-folder';
149
+
150
+ const addFolder = gulp.series(createFolder, hideFolder);
151
+
152
+ function index() {
153
+ const filename = 'vendor',
154
+ strs = [
155
+ cssComment,
156
+ `<!-- build:css ${stylesDir + filename}.css -->`,
157
+ '<!-- bower:css --><!-- endbower -->',
158
+ '<!-- endbuild -->'
159
+ ];
160
+ for (const { name } of cssExtensions)
161
+ strs.push('<link rel="stylesheet" href="' + stylesDir + stylesFilename + (name != 'css' ? '.' + name : '') + '.css' + '">');
162
+ strs.push(
163
+ endCssComment,
164
+ jsComment,
165
+ `<!-- build:js ${scriptsDir + filename}.js defer -->`,
166
+ '<!-- bower:js --><!-- endbower -->',
167
+ '<!-- endbuild -->',
168
+ '<!-- inject:js -->',
169
+ '<!-- endinject -->'
170
+ );
171
+ if (getSetting('html5Mode')) {
172
+ strs.unshift('<base href="/">');
173
+ strs.push(getScriptTag(html5ModeJsFile));
174
+ }
175
+ strs.push(endJsComment);
176
+
177
+ let stream = gulp.src(globs.srcJs);
178
+ if (getSetting('ng'))
179
+ stream = stream.pipe($.angularFilesort());
180
+
181
+ return gulp.src(globs.srcIndex)
182
+ .pipe($.injectString.before('</head>', tab + strs.join(nl + tab) + nl))
183
+ .pipe($.inject(stream, { relative: true, transform: filepath => getScriptTag(filepath) })).on('error', notifyError)
67
184
  .pipe($.wiredep())
68
185
  .pipe($.useref())
69
186
  .pipe(gulp.dest(globs.tmp));
70
187
  }
71
- buildIndex.displayName = 'build-index';
72
188
 
73
- function injectDomain() {
74
- return gulp.src(globs.tmp + jsFiles)
75
- .pipe(injStr.replace('{{AUTOFRONT_DOMAIN}}', domain))
189
+ function js() {
190
+ return gulp.src(globs.srcJs)
191
+ .pipe(replace('AUTOFRONT_ENV', JSON.stringify(envValue, undefined, tab)))
76
192
  .pipe(gulp.dest(globs.tmp));
77
193
  }
78
- injectDomain.displayName = 'inject-domain';
79
194
 
80
- const indexAndJs = gulp.series(buildIndex, injectDomain);
195
+ const indexAndJs = gulp.parallel(index, js);
81
196
 
82
- function styles() {
83
- return mergeStream(getStream('css'), getStream('less', $.less), getStream('scss', gulpSass, '@import "variables";'))
84
- .pipe($.concat(cssFile))
85
- .pipe(gulp.dest(globs.tmp + stylesDir))
86
- .pipe(browserSync.stream());
197
+ const css = getStylesTask('css');
87
198
 
88
- function getStream(ext, process, extraCode) {
89
- let stream = gulp.src(globs.src + stylesDir + cssFilename + '.' + ext, { allowEmpty: true });
90
- if (process)
91
- return stream
92
- .pipe(injStr.prepend((extraCode ? extraCode + nl : '') + '// bower:' + ext + nl + '// endbower' + nl))
93
- .pipe($.wiredep())
94
- .pipe(process()).on('error', notifyError);
95
- return stream;
199
+ const less = getStylesTask('less');
200
+
201
+ const scss = getStylesTask('scss');
202
+
203
+ const styles = gulp.parallel(css, less, scss);
204
+
205
+ function html5Mode(cb) {
206
+ if (getSetting('html5Mode'))
207
+ return $.addFiles([{
208
+ name: html5ModeJsFile,
209
+ content: `(function () {
210
+ angular.module('${getSetting('module')}')
211
+ .config(config);
212
+
213
+ function config($locationProvider) {
214
+ $locationProvider.html5Mode(true);
96
215
  }
216
+ })();`
217
+ }])
218
+ .pipe(gulp.dest(globs.tmp));
219
+
220
+ cb();
97
221
  }
222
+ html5Mode.displayName = 'html5-mode';
98
223
 
99
- function fonts() {
100
- return gulp.src(mainBowerFiles())
101
- .pipe(filter(['eot', 'otf', 'svg', 'ttf', 'woff', 'woff2'], true))
102
- .pipe(gulp.dest(globs.tmp + 'fonts/'));
224
+ function fonts(cb) {
225
+ const glob = require('main-bower-files')(getGlob(getSetting('extensions')));
226
+ if (glob.length)
227
+ return gulp.src(glob)
228
+ .pipe(gulp.dest(globs.tmp + getSetting('fontsFolder')));
229
+
230
+ cb();
103
231
  }
104
232
 
105
233
  function others() {
106
- const pugFilter = filter('pug');
107
- return gulp.src(globs.srcOthers)
108
- .pipe(pugFilter).pipe($.pug()).on('error', notifyError).pipe(pugFilter.restore)
109
- .pipe(gulp.dest(globs.tmp));
234
+ let stream = gulp.src(globs.srcOthers);
235
+ if (getSetting('pug')) {
236
+ const pugFilter = gulpFilter('pug');
237
+ stream = stream.pipe(pugFilter).pipe($.pug()).on('error', notifyError).pipe(pugFilter.restore);
238
+ }
239
+ return stream.pipe(gulp.dest(globs.tmp));
110
240
  }
111
241
 
112
242
  function about() {
113
243
  return gulp.src('package.json')
114
- .pipe($.about())
244
+ .pipe($.about({ inject: { environment: envName } }))
115
245
  .pipe(gulp.dest(globs.tmp));
116
246
  }
117
247
 
118
248
  const buildTmp = gulp.series(
119
- gulp.parallel(clean, manageDomain),
120
- gulp.parallel(indexAndJs, styles, fonts, others, about)
249
+ gulp.parallel(getEnv, removeFolder),
250
+ addFolder,
251
+ gulp.parallel(indexAndJs, styles, html5Mode, fonts, others, about)
121
252
  );
122
253
 
123
254
  function browser(cb) {
@@ -125,89 +256,218 @@ function browser(cb) {
125
256
  cb();
126
257
  }
127
258
 
259
+ function reload(cb) {
260
+ browserSync.reload();
261
+ cb();
262
+ }
263
+
128
264
  function watch() {
129
- gulp.watch(globs.srcIndexAndSrcJs, indexAndJs);
130
- gulp.watch(globs.srcStyles, styles);
131
- gulp.watch(globs.srcOthers, others).on('unlink', function (path) {
132
- gulp.src(path.replaceAll('\\', '/').replace(globs.src, globs.tmp).replace('.pug', '.html'), { read: false })
265
+ gulp.watch(globs.srcIndex, index);
266
+ gulp.watch(globs.srcJs)
267
+ .on('add', indexAndJs)
268
+ .on('change', gulp.series(js))
269
+ .on('unlink', gulp.series(index))
270
+ .on('unlink', path => { delFile(path); });
271
+
272
+ for (cssExt of cssExtensions)
273
+ gulp.watch(cssExt.glob, eval(cssExt.name));
274
+
275
+ gulp.watch(globs.srcOthers)
276
+ .on('add', gulp.series(others))
277
+ .on('change', gulp.series(others))
278
+ .on('unlink', path => { delFile(path, replaceExt); });
279
+
280
+ gulp.watch([globs.tmpAllFiles, '!' + globs.tmp + stylesDir + getGlob('css')], reload).on('unlink', () => { deleteEmpty(globs.tmp); });
281
+
282
+ function delFile(path, fn) {
283
+ path = path.replaceAll('\\', '/').replace(globs.src, globs.tmp);
284
+ if (fn)
285
+ path = fn(path);
286
+ gulp.src(path, { read: false })
133
287
  .pipe($.clean());
134
- deleteEmpty(globs.tmp);
135
- });
136
- gulp.watch([globs.tmpAllFiles, '!' + globs.tmp + stylesDir + cssFile], function (cb) {
137
- browserSync.reload();
138
- cb();
139
- });
288
+ }
289
+
290
+ function replaceExt(path) {
291
+ if (getSetting('pug'))
292
+ return path.replace('.pug', '.html');
293
+ return path;
294
+ }
140
295
  }
141
296
 
142
- gulp.task('serve', gulp.series(buildTmp, browser, watch));
297
+ gulp.task('serve', gulp.series(
298
+ gulp.parallel(setDefaultEnv, setVariables),
299
+ buildTmp, browser, watch
300
+ ));
143
301
 
144
- function cleanDist() {
145
- return delDir(globs.dist);
302
+ function removeFolderDist() {
303
+ return delDir([globs.dist, globs.hiddenDist]);
146
304
  }
147
- cleanDist.displayName = 'clean:dist';
305
+ removeFolderDist.displayName = 'remove-folder:dist';
148
306
 
149
307
  function copy() {
150
308
  return gulp.src(globs.tmpAllFiles)
309
+ .pipe($.size())
151
310
  .pipe(gulp.dest(globs.dist));
152
311
  }
153
312
 
154
- function buildTemplates() {
155
- return gulp.src([globs.dist + getGlob('html'), '!' + globs.dist + indexHtmlFile])
156
- .pipe($.cleanDest(globs.dist))
157
- .pipe(minifyHtml())
158
- .pipe($.angularTemplatecache(jsTemplatesFile, { module: 'app', transformUrl: function (url) { return url.slice(1); } }))
313
+ function templates() {
314
+ let stream = gulp.src(globs.distTmpls)
315
+ .pipe(gulpHtmlmin());
316
+ if (getSetting('template'))
317
+ stream = stream.pipe($.angularTemplatecache(jsTemplatesFile, { module: getSetting('module'), transformUrl: url => url.slice(1) }));
318
+ return stream.pipe(gulp.dest(globs.dist));
319
+ }
320
+
321
+ function indexDist() {
322
+ const replaces = Object.entries({
323
+ [cssComment]: `<!-- build:css ${cssFile} -->`,
324
+ [endCssComment]: '<!-- endbuild -->',
325
+ [jsComment]: `<!-- build:js ${jsFile} defer -->`,
326
+ [endJsComment]: '<!-- endbuild -->'
327
+ });
328
+ let stream = gulp.src(globs.distIndexFile);
329
+ if (getSetting('template') && fileExists(globs.dist + jsTemplatesFile))
330
+ stream = stream.pipe($.injectString.before(endJsComment, getScriptTag(jsTemplatesFile) + nl + tab));
331
+ for (const [search, str] of replaces)
332
+ stream = stream.pipe($.injectString.replace(search, str));
333
+ return stream
334
+ .pipe($.useref())
159
335
  .pipe(gulp.dest(globs.dist));
160
336
  }
161
- buildTemplates.displayName = 'build-templates';
337
+ indexDist.displayName = 'index:dist';
338
+
339
+ function rebase() {
340
+ const str = 'url(',
341
+ quotes = ["'", '"'];
342
+ let stream = gulp.src(globs.dist + cssFile)
343
+ .pipe(replace(str + '\\s*', str));
344
+ for (char of ['', ...quotes])
345
+ for (str2 of ['http://', 'https://', '//', '/', 'data:', '#'])
346
+ stream = stream.pipe(replace(str + char + str2, str + tab + char + str2));
347
+ stream = stream
348
+ .pipe(replace(str, str + stylesDir))
349
+ .pipe(replace(str + stylesDir + tab, str));
350
+ for (quote of quotes)
351
+ stream = stream.pipe(replace(str + stylesDir + quote, str + quote + stylesDir));
352
+ return stream.pipe(gulp.dest(globs.dist));
353
+ }
162
354
 
163
- function cleanTemplates() {
355
+ function cleanFiles() {
356
+ return gulp.src([
357
+ ...(getSetting('template') ? globs.distTmpls : []),
358
+ globs.dist + getGlob('css'), '!' + globs.dist + cssFile,
359
+ globs.dist + jsFiles, '!' + globs.dist + jsFile
360
+ ], { read: false })
361
+ .pipe($.clean());
362
+ }
363
+ cleanFiles.displayName = 'clean-files';
364
+
365
+ function cleanFolders() {
164
366
  return deleteEmpty(globs.dist);
165
367
  }
166
- cleanTemplates.displayName = 'clean-templates';
368
+ cleanFolders.displayName = 'clean-folders';
369
+
370
+ const clean = gulp.series(cleanFiles, cleanFolders);
371
+
372
+ const rebaseAndClean = gulp.parallel(rebase, clean);
373
+
374
+ const minify = gulp.parallel(
375
+ getMinifyTask('html', stream => stream.pipe(gulpHtmlmin())),
376
+ getMinifyTask('css', stream => stream.pipe($.postcss([require('cssnano')()]))),
377
+ getMinifyTask('js', stream => {
378
+ if (getSetting('ng'))
379
+ stream = stream.pipe($.ngAnnotate());
380
+ return stream.pipe($.terser());
381
+ }),
382
+ getMinifyTask(['png', 'jpg', 'gif', 'svg'], stream => stream.pipe($.imagemin()), 'img'),
383
+ getMinifyTask('json', stream => stream.pipe($.jsonmin()))
384
+ );
167
385
 
168
386
  function finishBuild() {
169
- const indexHtmlFilter = filter('html'),
170
- cssFilter = filter('css'),
171
- jsFilter = filter('js'),
172
- cssAndJsFilter = filter(['css', 'js']),
173
- imgFilter = filter(['png', 'jpg', 'gif', 'svg']),
174
- jsonFilter = filter('json');
387
+ const cssAndJsFilter = gulpFilter(['css', 'js']);
175
388
  return gulp.src(globs.dist + allFiles)
176
- .pipe(indexHtmlFilter).pipe(injStr.before('</body>', `<script src="${jsTemplatesFile}"></script>` + nl)).pipe(minifyHtml()).pipe(indexHtmlFilter.restore)
177
- .pipe(cssFilter).pipe($.cssnano({ zindex: false })).pipe(cssFilter.restore)
178
- .pipe(jsFilter).pipe($.ngAnnotate()).pipe($.terser()).pipe(jsFilter.restore)
179
389
  .pipe(cssAndJsFilter).pipe($.rev()).pipe($.revDeleteOriginal()).pipe(cssAndJsFilter.restore)
180
390
  .pipe($.revReplace())
181
- .pipe(imgFilter).pipe($.imagemin()).pipe(imgFilter.restore)
182
- .pipe(jsonFilter).pipe($.jsonmin()).pipe(jsonFilter.restore)
183
391
  .pipe($.size({ showFiles: true }))
184
392
  .pipe(gulp.dest(globs.dist));
185
393
  }
186
394
  finishBuild.displayName = 'finish-build';
187
395
 
188
- gulp.task('build', gulp.series(buildTmp, cleanDist, copy, buildTemplates, cleanTemplates, finishBuild));
396
+ gulp.task('build', gulp.series(
397
+ setVariables,
398
+ gulp.parallel(buildTmp, removeFolderDist),
399
+ copy, templates, indexDist, rebaseAndClean, minify, finishBuild
400
+ ));
401
+
402
+ function hideFolderDist(cb) {
403
+ hideDir(globs.dist);
404
+ cb();
405
+ }
406
+ hideFolderDist.displayName = 'hide-folder:dist';
189
407
 
190
408
  function browserDist(cb) {
191
- browserSyncInit(globs.dist);
409
+ browserSyncInit(globs.hiddenDist);
192
410
  cb();
193
411
  }
194
412
  browserDist.displayName = 'browser:dist';
195
413
 
196
- gulp.task('serve:dist', gulp.series('build', browserDist));
197
-
198
- gulp.task('default', gulp.task('serve'));
414
+ gulp.task('serve:dist', gulp.series(setDefaultEnv, 'build', hideFolderDist, browserDist));
199
415
 
200
- function html5Mode() {
201
- const prefix = '/';
202
- stylesDir = prefix + stylesDir;
203
- jsTemplatesFile = prefix + jsTemplatesFile;
204
- }
416
+ gulp.task('default', gulp.series('serve'));
205
417
 
206
418
  function getGlob(ext = '*') {
207
419
  const glob = '**/*.';
208
420
  if (typeof ext == 'string')
209
421
  return glob + ext;
210
- return glob + '{' + ext.join() + '}';
422
+ return glob + '{' + ext.join() + ',}';
423
+ }
424
+
425
+ function getSetting(name) {
426
+ switch (name) {
427
+ case 'pug':
428
+ return getValue('html');
429
+ case 'cssFolder':
430
+ case 'filename':
431
+ case 'cssOrder':
432
+ return getValue('css');
433
+ case 'less':
434
+ case 'scss':
435
+ return getValue('css', true);
436
+ case 'lessOrder':
437
+ return getValue('css.less', true, true);
438
+ case 'scssOrder':
439
+ case 'variables':
440
+ return getValue('css.scss', true, true);
441
+ case 'fontsFolder':
442
+ case 'extensions':
443
+ return getValue('css.fonts');
444
+ case 'ng':
445
+ return getValue('js', true);
446
+ case 'module':
447
+ case 'html5Mode':
448
+ case 'template':
449
+ return getValue('js.ng', true, true);
450
+ case 'envs':
451
+ return getValue('js');
452
+ }
453
+
454
+ function getValue(str, withoutDefault, onlyIfFalsy) {
455
+ for (const str of ['Folder', 'Order'])
456
+ if (name.endsWith(str))
457
+ name = str.toLowerCase();
458
+
459
+ const nameStr = str + '.' + name,
460
+ value = eval('settings.' + nameStr.replaceAll('.', '?.'));
461
+ if (withoutDefault) {
462
+ if (!onlyIfFalsy || !getSetting(str.split('.').pop()))
463
+ return value;
464
+ }
465
+ return value ?? eval('defSettings.' + nameStr);
466
+ }
467
+ }
468
+
469
+ function fileExists(path) {
470
+ return fs.existsSync(path);
211
471
  }
212
472
 
213
473
  function delDir(glob) {
@@ -215,14 +475,62 @@ function delDir(glob) {
215
475
  .pipe($.clean());
216
476
  }
217
477
 
218
- function filter(ext, isUnrestored) {
219
- return $.filter(getGlob(ext), { restore: !isUnrestored });
478
+ function hideDir(glob) {
479
+ hidefile.hideSync(glob, error => notifyError(error));
480
+ }
481
+
482
+ function getScriptTag(src) {
483
+ return `<script src="${src}" defer></script>`;
484
+ }
485
+
486
+ function replace(search, str) {
487
+ for (const char of ['$', '.', '/', '('])
488
+ search = search.replaceAll(char, '\\' + char);
489
+ return $.injectString.replace(search, str);
490
+ }
491
+
492
+ function getStylesTask(ext) {
493
+ const fn = cb => {
494
+ const cssExt = cssExtensions.find(({ name }) => name == ext);
495
+ if (cssExt) {
496
+ const stylesFile = stylesFilename + '.' + ext,
497
+ srcStylesFile = globs.src + stylesDir + stylesFile,
498
+ isPreprocessor = cssExt.isPreprocessor,
499
+ extraCode = cssExt.getExtraCode(),
500
+ sep = nl + nl,
501
+ content = (extraCode ? extraCode + sep : '') + (isPreprocessor ? '// bower:' + ext + nl + '// endbower' : '');
502
+ let stream;
503
+ if (!fileExists(srcStylesFile))
504
+ stream = $.addFiles([{
505
+ name: stylesFile,
506
+ content
507
+ }]);
508
+ else
509
+ stream = gulp.src(srcStylesFile)
510
+ .pipe($.injectString.prepend(content ? content + sep : ''));
511
+ if (isPreprocessor)
512
+ stream = stream.pipe($.wiredep());
513
+ stream = stream.pipe(cssExt.process()).on('error', notifyError);
514
+ if (isPreprocessor)
515
+ stream = stream.pipe($.rename({ suffix: '.' + ext }));
516
+ return stream
517
+ .pipe(gulp.dest(globs.tmp + stylesDir))
518
+ .pipe(browserSync.stream());
519
+ }
520
+
521
+ cb();
522
+ };
523
+ fn.displayName = ext;
524
+ return fn;
220
525
  }
221
526
 
222
527
  function browserSyncInit(path) {
223
528
  browserSync.init({ server: path });
224
529
  }
225
530
 
226
- function minifyHtml() {
227
- return $.htmlmin({ collapseWhitespace: true, conservativeCollapse: true });
531
+ function getMinifyTask(ext, getProcessedStream, str) {
532
+ const fn = () => getProcessedStream(gulp.src(globs.dist + getGlob(ext)))
533
+ .pipe(gulp.dest(globs.dist));
534
+ fn.displayName = 'minify-' + (str || ext);
535
+ return fn;
228
536
  }
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "autofront",
3
- "version": "2.2.3",
4
- "description": "Automatisation of front-end by Gulp and Bower.",
3
+ "version": "3.0.1",
4
+ "description": "Automation of front-end by Gulp and Bower.",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "serve": "gulp",
8
- "serve:dist": "gulp serve:dist",
9
- "build": "gulp build",
10
- "test": "echo \"Error: no test specified\" && exit 1"
8
+ "serve:dist": "gulp serve:dist --env=preproduction",
9
+ "build": "gulp build"
11
10
  },
12
11
  "repository": {
13
12
  "type": "git",
@@ -18,7 +17,7 @@
18
17
  "pug",
19
18
  "css",
20
19
  "less",
21
- "sass",
20
+ "scss",
22
21
  "javascript",
23
22
  "angularjs"
24
23
  ],
@@ -29,47 +28,40 @@
29
28
  },
30
29
  "homepage": "https://github.com/mvicens/autofront#readme",
31
30
  "dependencies": {
32
- "browser-sync": "^2.26.3",
33
- "delete-empty": "^2.0.0",
34
- "get-gulp-args": "^0.0.1",
35
- "gulp": "^4.0.2",
36
- "gulp-about": "^1.1.0",
37
- "gulp-angular-filesort": "^1.2.1",
38
- "gulp-angular-templatecache": "^2.2.3",
39
- "gulp-clean": "^0.4.0",
40
- "gulp-clean-dest": "^0.2.0",
41
- "gulp-concat": "^2.6.1",
42
- "gulp-cssnano": "^2.1.3",
43
- "gulp-filter": "^5.1.0",
44
- "gulp-htmlmin": "^4.0.0",
45
- "gulp-imagemin": "^4.1.0",
46
- "gulp-inject": "^4.3.2",
47
- "gulp-inject-string": "^1.1.1",
48
- "gulp-jsonmin": "^1.2.0",
49
- "gulp-less": "^3.5.0",
50
- "gulp-load-plugins": "^1.5.0",
51
- "gulp-ng-annotate": "^2.1.0",
52
- "gulp-notify": "^3.2.0",
53
- "gulp-pug": "^4.0.1",
54
- "gulp-rev": "^8.1.1",
55
- "gulp-rev-delete-original": "^0.2.3",
56
- "gulp-rev-replace": "^0.4.4",
57
- "gulp-sass": "^5.0.0",
58
- "gulp-size": "^3.0.0",
59
- "gulp-terser": "^1.1.7",
60
- "gulp-useref": "^3.1.6",
61
- "gulp-wiredep": "^1.2.0",
62
- "main-bower-files": "^2.13.1",
63
- "merge-stream": "^1.0.1",
64
- "sass": "^1.38.2"
65
- },
66
- "domains": {
67
- "local": "http://localhost:8081/",
68
- "development": "http://dev.mydomain/",
69
- "production": "http://mydomain/"
70
- },
71
- "domainAliases": {
72
- "prod": "production",
73
- "dev": "development"
31
+ "browser-sync": "2.27.10",
32
+ "cssnano": "5.1.14",
33
+ "delete-empty": "2.0.0",
34
+ "get-gulp-args": "0.0.1",
35
+ "gulp": "4.0.2",
36
+ "gulp-about": "1.1.0",
37
+ "gulp-add-files": "1.0.0",
38
+ "gulp-angular-filesort": "1.2.1",
39
+ "gulp-angular-templatecache": "3.0.1",
40
+ "gulp-clean": "0.4.0",
41
+ "gulp-cssimport": "7.0.0",
42
+ "gulp-filter": "7.0.0",
43
+ "gulp-htmlmin": "5.0.1",
44
+ "gulp-imagemin": "7.1.0",
45
+ "gulp-inject": "5.0.5",
46
+ "gulp-inject-string": "1.1.2",
47
+ "gulp-jsonmin": "1.2.0",
48
+ "gulp-less": "5.0.0",
49
+ "gulp-load-plugins": "2.0.8",
50
+ "gulp-ng-annotate": "2.1.0",
51
+ "gulp-notify": "4.0.0",
52
+ "gulp-postcss": "9.0.1",
53
+ "gulp-pug": "5.0.0",
54
+ "gulp-rename": "2.0.0",
55
+ "gulp-rev": "9.0.0",
56
+ "gulp-rev-delete-original": "0.2.3",
57
+ "gulp-rev-replace": "0.4.4",
58
+ "gulp-sass": "5.1.0",
59
+ "gulp-size": "4.0.1",
60
+ "gulp-terser": "2.1.0",
61
+ "gulp-useref": "5.0.0",
62
+ "gulp-wiredep": "1.2.0",
63
+ "hidefile": "3.0.0",
64
+ "main-bower-files": "2.13.3",
65
+ "sass": "1.56.1"
74
66
  }
75
67
  }