Gulp-Webpack Loaders returning loader source code? - gulp

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.

Related

Gulp require alias

I am looking for a safe way of doing require aliases using gulp.
The idea is similar to what webpack offers with resolve alias.
For example, I put on my source code something like require('#plugin/utils') and it is translated to something of my choice, like require('$/plugins/longer/namespace/utils'). You probably have noticed that it does not match to any actual file path, and that is intentional (they are tiddlywiki files if anyone is interested).
The best thing I found is gulp-replace, but that relies on strings replacements at worst and regular expressions at best.
Ideally I would want something more reliable, something that is AST aware,so I'm sure that I never replace the wrong string (for example, a template string).
I am also using babel, so if there is a babel plugin that I can use I will also be happy about that.
As a last resort I may try to write some babel plugin or a gulp plugin using esprima, but esprima is not up to modern JS standard (doesn't parse object spread) and I would prefer creating another tool.
Thanks in advance
Finally I found a babel module (babel-plugin-module-resolver) that I can integrate with gulp, and with some extra configuration magic with eslint.
So, this is what I added to my gulp pipeline (simplified)
const babelCfg = {
plugins: [[
require.resolve('babel-plugin-module-resolver'),
{
root: [ `${pluginSrc}/**` ],
alias: { '#plugin': `$:/plugins/${pluginNamespace}` },
loglevel: 'silent',
}
]],
};
return gulp
.src(`${pluginSrc}/**/*.js`)
.pipe(babel(babelCfg))
.pipe(gulp.dest(outPath.dist));
That converts all the references to require('#plugin/xxxx') with the proper path.
With some extra configuration you can even make eslint warn you about bad path resolutions.
You need to configure it differently because eslint needs the real path, while the output files needs a special namespace. After installing both eslint-import-resolver-babel-module and eslint-plugin-import this is what you should add to your eslint config to make it work:
plugins:
- import
env:
node: true
browser: true
settings:
import/resolver:
babel-module:
root: ./src/**
alias:
"#plugin": ./src/the/real/path
rules:
import/no-unresolved: [2, { commonjs: true }]

How do I get a simple Vue compilation going in Gulp?

I already use gulp in my workflow, and I don't currently use webpack or browserify, but it seems that compiling Vue 2.x components requires one or the other, there are no actively-maintained mechanisms for compiling Vue components directly as gulp tasks.
I've searched and can't seem to find a working reference for simply compiling a directory with *.vue components into a single JavaScript file that I can then link from my pages. I just want to create and use some components, I'm not creating SPAs.
Here's what I have:
gulpfile.js
const scriptDestFolder = "\\foo\\";
const browserify = require('browserify');
const source = require('vinyl-source-stream');
const gulp = require("gulp");
const vueify = require('vueify');
gulp.task('vue', function () {
return browserify({
entries: ['./vuecomponents.js'],
transform: [vueify]
})
.bundle()
.pipe(source('vue-bundle.js'))
.pipe(gulp.dest(scriptDestFolder));
});
vuecomponents.js
var Vue = require('vue');
var App = require('./vue/app.vue');
The app.vue file is the same as the example here. I have no intention of actually having an "app" component, I'm just trying to get a sample going, I would replace this with a list of my single-file components.
And here's the result:
Error: Parsing file \\blah\vue\app.vue:
'import' and 'export' may only appear at the top level (14:0)
I'm stumped. I think browserify is trying to parse the raw vue code before compilation, but again, I'm a complete newbie at browserify.
I actually adapted a plugin for this last year, based on vueify but without browserify. I think it does exactly what you want.
You can find it here: https://www.npmjs.com/package/gulp-vueify2
var vueify = require('gulp-vueify2');
gulp.task('vueify', function () {
return gulp.src('components/**/*.vue')
.pipe(vueify(options))
.pipe(gulp.dest('./dist'));
});
For people that don't need to use gulp, there are however much more consistent solutions to compile vue components, such as bili for librairies or parceljs for apps.
Last but not least, if you are ready to enforce some conventions, Nuxt is the perfect way to compile your app with minimal config work and optional server-side rendering built-in.

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.

Yii2 assets and 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.

With gulp, are watch tasks guaranteed to run before other tasks?

I have a gulp watch task that uses gulp-sass to convert SASS to CSS. For development, separated CSS files are all I want.
For release, I have a min tasks that uses gulp-cssmin and concat to bundle and minify the CSS. However, the min task doesn't deal with the SASS files. It assumes they have already been converted to CSS.
Is this a valid assumption? What if an automated build gets the latest source (which does not have .scss files) and runs min? Is there a race condition here as to whether the watch task will run in time for min to pick up the SASS files?
If your min task is also watching the SASS files, your assumption is not necessarily valid. By default, all the tasks will run at the same time. You can however define dependencies in your task, so that a task does not start until another task is finished. This could solve your problem. The documentation about dependencies can be found here.
There are also two other solutions:
Watch the CSS files for the min task.
Run the logic in your min task at the end of the task that compiles the SASS.
Edward! Better use optional minification to prevent extra reading from the disk.
var env = require('minimist')(process.argv.slice(2));
var noop = require('readable-stream/passthrough').bind(null, { objectMode: true });
gulp.task('style', function () {
return gulp.src('...')
.pipe(process())
.pipe(env.min ? uglify() : noop())
.pipe(gulp.dest('...'))
});
Also I don't recommend these tools from gulp-util which will be deprecated
Even if gulp guaranteed that it would wait for watch tasks to complete before starting dependent tasks, a race could still occur during the interval from when a source file is changed until the OS notifies gulp. So I decided not to use the SASS → CSS transform output. For as infrequently as I need to build the minimized versions, there's no payoff for saving those milliseconds.
Instead I used stream-combiner2 to reuse the transform logic:
var combiner = require('stream-combiner2');
function scssTransform() {
return combiner(
sourcemaps.init(),
sass(),
sourcemaps.write());
}
I use the transform for my non-mimized "sandbox" for local development:
gulp.task('sandbox:css', function () {
return gulp.src(paths.scss)
.pipe(scssTransform())
.pipe(gulp.dest(dirs.styles));
});
My task for serving the site locally depends on and watches the task:
gulp.task('serve.sandbox', ['sandbox:css' /* ... more ... */], function () {
// ... Start the web server ...
gulp.watch(paths.scss, ['sandbox:css']);
// ... Watch more stuff ...
});
I also use the transform for my minimized deployment:
gulp.task('deploy:css', function () {
return gulp.src(paths.scss)
.pipe(scssTransform())
.pipe(concat(files.cssMin))
.pipe(cssmin())
.pipe(gulp.dest(dirs.deploy));
});