Yii2 assets and gulp - gulp

I learn Yii2 and tried to use gulp with it in way like described here. I created gulp config with following content:
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var cssMin = require('gulp-css');
var rename = require('gulp-rename');
var minimist = require('minimist');
var options = minimist(process.argv.slice(2), {string: ['src', 'dist']});
var destDir = options.dist.substring(0, options.dist.lastIndexOf("/"));
var destFile = options.dist.replace(/^.*[\\\/]/, '');
// Use `compress-js` task for JavaScript files 
gulp.task('compress-js', function () {
    return gulp.src(options.src)
        .pipe(uglify())
        .pipe(rename(destFile))
        .pipe(gulp.dest(destDir))
});
// Use `compress-css` task for CSS files
gulp.task('compress-css', function () {
    return gulp.src(options.src)
        .pipe(cssMin())
        .pipe(rename(destFile))
        .pipe(gulp.dest(destDir))
});
I use this file for my bundle:
<?php
namespace app\assets;
use yii\web\AssetBundle;
class AppAsset extends AssetBundle
{
    public $basePath = '#webroot';
    public $baseUrl = '#web';
    public $css = [
        'css/site.css',
    ];
    public $js = [
    ];
    public $jsOptions = [
        'position' => \yii\web\View::POS_HEAD
    ];
    public $depends = [
        'yii\web\YiiAsset',
        'yii\bootstrap\BootstrapAsset',
    ];
}
And, after all, I use this config for asset command
<?php
Yii::setAlias('#webroot', str_replace('\\', '/',  __DIR__) . '/web');
Yii::setAlias('#web', '/');
return [
    'jsCompressor' => 'gulp compress-js --gulpfile gulpfile.js --src {from} --dist {to}',
    'cssCompressor' => 'gulp compress-css --gulpfile gulpfile.js --src {from} --dist {to}',
    'bundles' => [
        'app\assets\AppAsset'
    ],
    'targets' => [
        'all' => [
            'class' => 'yii\web\AssetBundle',
            'basePath' => '#webroot/assets',
            'baseUrl' => '#web/assets',
            'js' => 'combined-{hash}.js',
            'css' => 'combined-{hash}.css',
            'depends' => [
            ],
        ],
    ],
    // Asset manager configuration:
    'assetManager' => [
        'basePath' => '#webroot/assets',
        'baseUrl' => '#web/assets',
        'linkAssets' => true
    ],
];
But, when I try to run php yii asset assets-config.php config/assets-prod.php combined files and configuration file config/assets-prod.php generate, but in web/assets directory exists a lot of symlinks (or direct copies if linkAssets === true) of files and folders, which is bundle dependencies themselves. They generate via publish() method of AssetManager. Why Yii don't clean these folders and files after compilation process? Or maybe I do something wrong?

Your script or css files can depend on their sources. For instance you combine css files. One file (from folder "foldername" its important) have following rule
i.sprite-icons {
url(./icons.png)
}
yii concatenate files & move them into "/assests" folder. So Yii also modifies urls. As a result you have following css rule.
i.sprite-icons {
url(./foldername/icons.png)
}
Yii run compressor only after it concatenates files. In your case - gulp.

Related

How to serve a json file with parcel without bundling it?

I'm making a project with parcel and typescript. It works great, but for one library I'm using, I would need to host a bunch of .json-files at a fixed directory:
The files look as following:
index.html
index.ts
tiles/
| file.json
| file0.json
| subdirectory with *.json
In package.json, I include them as parcel *.html tiles/* (for start) and parcel build index.html tiles/*, but this results in the json files to be build into some .js file. I however need them to be served as is.
Any hints on how to tell parcel not to bundle them?
There is a npm-package doing exactly this: https://www.npmjs.com/package/parcel-plugin-static-files-copy
npm install -D parcel-plugin-static-files-copy to install (for development only)
Then, in package.json, add:
"staticFiles": {
"staticPath": [
{
"staticPath": "tiles", -- copy all files from this directory at the root from your project...
"staticOutDir": "tiles/" -- ... to this directory in dist/, so it becomes dist/tiles/<files>
}
]
}
```
Note that you have to define a `staticPath` in the list `staticPath`, this is a bit confusing at first.
You can override the transformer plugin used for JSON files in the .parcelrc file. It defaults to using #parcel/transformer-json, but you can use #parcel/transformer-raw to treat JSON files as assets.
.parcelrc
{
"extends": "#parcel/config-default",
"transformers": {
"*.json": ["#parcel/transformer-raw"]
}
}
If you're using Parcel 2, you can do something like this:
import jsonUrl from 'url:./data.json'
// Fetch the file asynchronously from the URL
fetch(jsonUrl)
.then(response => response.json())
.then(json => ...)
... etc. ...

Reading application settings from JSON file in angular application

I have implemented the application configuration to be read from JSON file from my angular application so that it is easily configurable post deploment.
We use Octopus deployment tool to deploy the angular application. As you are aware the having he enviornment.ts file gets generated as js file and it
is very difficult to manipulate the settings in Octopus by reading the JS file. Hence I have created config.JSON file that would be outputted to the dist folder and
Octopus deploy can consume the JSON file to make changes whenever needed.
Currently the application is reading values from enviornment ts file which in turn is reading the values set in the Config.JSON file.
I would like to know if my approach is correct ?
Config.JSON
{
"settings": {
"production": false,
"userIdleMinutes": "10",
"corePingIntervalSeconds": "10",
"baseUrl": "http://localhost:57973",
"loginUrl": "/Login",
"adminUrl": "/Admin"
}
}
enviornment.ts
import config from '../assets/config.json'
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.
export const environment = {
production: config.settings.production,
baseUrl: config.settings.baseUrl,
loginUrl:config.settings.loginUrl,
adminUrl: config.settings.adminUrl,
userIdleMinutes: config.settings.userIdleMinutes,
corePingIntervalSeconds: config.settings.corePingIntervalSeconds
};
if you are using octopus, instead of doing that, in your environment.prod.ts add some tokens and replace them on each environment by octopus
(right now I don't have access to show you how, but something like below)
environment.prod.ts
export const environment = {
production: #{production},
baseUrl: "#{baseUrl}",
//... rest of your configs
};
then add a step to replace these variables with the variables defined in environment in main.*.js file on each deployment

File injection with gulp, pick only some files from folder

I use Gulp for injecting my js files into index.html. I have the following structure of my js resources:
js
|-ace-builds
|-src
|-ace.js
|-ext-beautify.js
|-ext-chromevox.js
|-ext-elastic_tabstops_lite.js
|-...
|-angular
|-angular.js
|-angular-ui-ace
|-ui-ace.js
|-...
The problem is that from the whole ace-builds folder I need to inject only one file ace.js. Of course, one of the possible solution is to list all injected files manually, but I would like to make the injector definition quite compact and flexible.
Questions is: is it possible with gulp to make such file injection, ingoring other files in the folder and if yes, how?
I tried the following code, also placing the lines (1) and (2) in reverse order, but it has not worked, the ace.js is not included.
gulp.task('index', function () {
var target = gulp.src('./app/html/index.html');
var sources = gulp.src([
'app/js/*.js',
'!app/js/ace-builds/**/*', // (1)
'app/js/ace-builds/src-noconflict/ace.js' // (2)
], { read: false });
return target.pipe(inject(sources))
.pipe(gulp.dest('./app/html'));
});
Nothing in your gulp.src's actually reads the folder that ace.js is in. Why not just include app/js/**/ace.js? With no negation. And, by the way, the negation will always be performed last no matter where you have it listed. That is why you never pick up ace.js.

Gulp-Webpack Loaders returning loader source code?

Newbie. I'm setting up gulp-webpack to run in a Gulp task, and I'm starting simple by processing a test "less" file. I npm-installed gulp-webpack, webpack, and also the webpack loaders less-loader, css-loader, and style-loader. For some reason, my output css file isn't ... instead it's a js file containing what appears to be source code for a loader itself. Do I need to require the webpack loaders within the webpack config file?
My gulpfile.js:
var gulpwebpack = require('gulp-webpack');
gulp.task('go2',function(){
return gulp.src('src/homesMenuAngular/css/*.less')
.pipe(gulpwebpack( require('./webpack.config.js') ))
.pipe(gulp.dest('builds/homesMenuAngular/css'));
});
My webpack.config.js:
// no require statements
module.exports = {
module: {
loaders: [
{
test: /\.less$/,
loader: "style!css!less"
}
]
}
};
So, most experienced webpackers are probably rolling their eyes, because yes, webpack does output javascript that injects all the other resources into the page. I was thinking "let's use a webpack loader to convert less to css" and "let's use gulp" to automate the whole build process but I hadn't taken a deep enough dive into how webpack works specifically that it bundles everything into 1 or more js files.

Using ES6 `import` with CSS/HTML files in Meteor project: bug or feature?

I am currently learning Meteor and I found out something that intrigued me.
I can load HTML and CSS assets from a JS file using the import statement.
import '../imports/hello/myapp.html';
import '../imports/hello/myapp.css';
import * as myApp from '../imports/hello/myapp.js';
This was a surprise to me so I ran to google but could not find this behavior documented in the specification for ES6 import or in Meteor's Docs.
So my questions are:
Can I rely on this behavior to build my apps?
Will my app will break when Meteor gets around to fix it -- if it's a bug --?
Notes
I am using Meteor v1.3, not sure if this works also with previous versions.
You can download the app to see this behavior from Github
After going through the implementation of the built files for my app
I found out why this works.
HTML
Files are read from the file system and their contents added to the global Template object, e.g.,
== myapp.html ==
<body>
<h1>Welcome to Meteor!</h1>
{{> hello}}
</body>
results in the following JS code:
Template.body.addContent((function () {
var view = this;
return [
HTML.Raw("<h1>Welcome to Meteor!</h1>\n\n "),
Spacebars.include(view.lookupTemplate("hello"))
];
}));
Which is wrapped in a function with the name of the file as it's key:
"myapp.html": function (require, exports, module) {
Template.body.addContent((function () {
var view = this;
return [
HTML.Raw("<h1>Welcome to Meteor!</h1>\n\n "),
Spacebars.include(view.lookupTemplate("hello"))];
}));
Meteor.startup(Template.body.renderToDocument);
Template.__checkName("hello");
Template["hello"] = new Template("Template.hello", (
function () {
var view = this;
return [
HTML.Raw("<button>Click Me</button>\n "),
HTML.P("You've pressed the button ",
Blaze.View("lookup:counter",
function () {
return Spacebars.mustache(view.lookup("counter"));
}), " times.")
];
}));
},
So all of our HTML is now pure JS code which will be included by using require like any other module.
CSS
The files are also read from the file system and their contents are embedded also in JS functions, e.g.
== myapp.css ==
/* CSS declarations go here */
body {
background-color: lightblue;
}
Gets transformed into:
"myapp.css": ["meteor/modules", function (require, exports, module) {
module.exports = require("meteor/modules").addStyles("/* CSS declarations go here */\n\nbody {\n background-color: lightblue;\n}\n");
}]
So all of our CSS is also now a JS module that's again imported later on by using require.
Conclusion
All files are in one way or another converted to JS modules that follow similar rules for inclusion as AMD/CommonJS modules.
They will be included/bundled if another module refers to them. And since all of them are transformed to JS code
there's no magic behind the deceitful syntax:
import '../imports/hello/myapp.html';
import '../imports/hello/myapp.css';
They both are transpiled to their equivalent forms with require once the assets have been transformed to JS modules.
Whereas the approach of placing static assets in the imports directory is not mentioned in the official documentation,
this way of importing static assets works.
This seems to be at the core of how Meteor works so I'd bet this functionality is going to be there for a long while.
I don't know if to call this a feature maybe a more appropriate description is unexpected consequence but that would
only be true from the user's perspective, I assume the people who wrote the code understood this would happen and perhaps even
designed it purposely this way.
One of the features in Meteor 1.3 is lazy-loading where you place your files in the /imports folder and will not be evaluated eagerly.
Quote from Meteor Guide:
To fully use the module system and ensure that our code only runs when
we ask it to, we recommend that all of your application code should be
placed inside the imports/ directory. This means that the Meteor build
system will only bundle and include that file if it is referenced from
another file using an import.
So you can lazy load your css files by importing them from the /imports folder. I would say it's a feature.
ES6 export and import functionally are available in Meteor 1.3. You should not be importing HTML and CSS files if you are using Blaze, the current default templating enginge. The import/export functionality is there, but you may be using the wrong approach for building your views.