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.
Related
Below you can see simplified view of an issue. Basically, I'm able to call task1.js using gulp.series in tasks task2,3.js, but once I add same code to call task1.js in task4.js - Task never defined: task1 error gets thrown.
There are more tasks in the tasks folder than in file structure example below.
I've got three tasks,
...
/tasks
build.js
clean.js
dev.js
gulpfile.babel.js
...
all of them required in gulpfile.babel.js using the require-dir package
import requireDir from 'require-dir';
requireDir('./tasks', {recurse: true});
This allows me to call a task from clean.js at dev.js, and it works fine.
import gulp from 'gulp';
gulp.task('dev', gulp.series('clean');
But after I add same code structure at build.js.
import gulp from 'gulp';
gulp.task('build', gulp.series('clean');
it somehow breaks gulp stream (I guess), so now on any task call I get:
$gulp dev
-AssertionError [ERR_ASSERTION]: Task never defined: clean.
$gulp -v
[11:50:11] CLI version 2.0.1
[11:50:11] Local version 4.0.0
For those migrating from gulp v3 to v4 or are using gulp.task() to define tasks in gulp v4 and get this error message: Task never defined, the problem usually lies here:
Forward references
A forward reference is when you compose tasks, using string
references, that haven't been registered yet. This was a common
practice in older versions, but this feature was removed to achieve
faster task runtime and promote the use of named functions. In newer
versions, you'll get an error, with the message "Task never defined",
if you try to use forward references. You may experience this when
trying to use exports for your task registration and composing tasks
by string. In this situation, use named functions instead of string
references.
During migration, you may need to use the forward reference registry.
This will add an extra closure to every task reference and
dramatically slow down your build. Don't rely on this fix for very
long.
From gulpjs documentation re: gulp.series and gulp.parallel documentation.
Here is what that means. There are two ways to create tasks:
1. gulp.task('someStringAsTask', function() {..})
2. function myNamedFunction () {…}
When you use version 1 (gulp.task…) you cannot refer to that task by its string name until it has been registered. So you cannot do this:
exports.sync = gulp.series('sass2css', serve, watch);
// or gulp.task('dev', gulp.series('sass2css', serve, watch); doesn't work either
gulp.task('sass2css', function() {
return gulp.src(paths.sass.stylesFile)
.pipe(sass().on("error", sass.logError))
.pipe(gulp.dest(paths.css.temp))
.pipe(reload({ stream: true }));
})
Results in
AssertionError [ERR_ASSERTION]: Task never defined: sass2css
That is a forward reference, composing a task (using gulp.series or gulp.parallel) and referring to a task by its string name (in the above case 'sass2css') before it has been registered. (calling "gulp.task(…..)" is the act of registering) Putting the gulp.task('sass2css',...) first fixes the problem.
If you use version two of defining a task:
function sass2css() {
return gulp.src(paths.sass.stylesFile)
.pipe(sass().on("error", sass.logError))
.pipe(gulp.dest(paths.css.temp))
.pipe(reload({ stream: true }));
}
you are now using a named function to register a task and do not need to use its name as a string. So this now works:
exports.sync = gulp.series(sass2css, serve, watch);
// gulp.task('dev', gulp.series(sass2css, serve, watch); this also works
followed by (or preceded by - either works):
function sass2css() {
return gulp.src(paths.sass.stylesFile)
.pipe(sass().on("error", sass.logError))
.pipe(gulp.dest(paths.css.temp))
.pipe(reload({ stream: true }));
}
The original OP used this and it worked:
import gulp from 'gulp';
gulp.task('dev', gulp.series('clean');
Noted that clean.js got imported before dev.js so that was okay.
This didn't work:
import gulp from 'gulp';
gulp.task('build', gulp.series('clean');
because the string-referenced task, 'clean' gets imported (and thus registered) after build.js where it is referenced - thus creating an illegal forward reference to a string-referenced task.
So there are two standard ways to fix this error:
Use named functions to define tasks not gulp.task('someTask',...). Then it doesn't matter the order of using those named functions when composing other tasks, i.e., when using gulp.series or gulp.parallel. And there are other advantages to using named functions, such as passing arguments, so this is the best option.
If you do use the older gulp v3 gulp.task method of creating tasks with string references, be careful to not refer to those tasks until after the task is actually created.
Also see my answer at task never defined error for fixing another problem which results in the same error message. Specifically using gulp.task('someTask', ['anotherTask'], function(){}) synatx in a gulp4 file.
The series and parallel functions of gulp 4 do not create a task definition as its README seems to suggest, but instead they both run the tasks in parameter. In order to work as intended, one need to surround the call with a closure.
So, to fix the excerpt
gulp.task('build', gulp.series('clean'));
it is necessary to add the closure:
// Older EcmaScripts:
gulp.task('build', function() { return gulp.series('clean') });
// EcmaScript 6:
gulp.task('build', () => gulp.series('clean'));
I had a similar setup where I had recursively require'd all tasks under a directory. And after updating to gulp 4 started getting error Task never defined.
I tried Pedro solution, but this caused another error:
The following tasks did not complete: default
Did you forget to signal async completion?
The solution was fairly simple for me, just import the missing tasks.
import gulp from 'gulp';
import './clean';
gulp.task('build', gulp.series('clean'));
The easiest solution might be using the official undertaker-forward-reference package:
const gulp = require("gulp");
const FwdRef = require("undertaker-forward-reference");
gulp.registry(FwdRef()); // Or gulp.registry(new FwdRef());
gulp.task("firstRegisteredTask", gulp.series("laterRegisteredTask")); // Works thanks to undertaker-forward-reference
gulp.task("laterRegisteredTask", () => {
return gulp.src("someGlob").pipe(gulp.dest("someFolder"));
});
This solution might negatively affect performance though (source):
This will add an extra closure to every task reference and dramatically slow down your build.
If I have the files
client/
a.js
bob.js
bad.js
And the gulp task
gulp.task('copy', function() {
return gulp.src(['client/*.js', '!client/b*.js', 'client/bad.js'])
.pipe(gulp.dest('public'));
});
then according to the documentation we should copy a.js and bad.js. However, when I run this with gulp v3.9.1, it only copies a.js.
Is this a known bug? Is there a way to do this?
It's not a bug, the documentation is just wrong. The newest version of gulp is gulp#3.9.1 which uses vinyl-fs#0.3.14. The behavior you're referring to wasn't introduced until vinyl-fs#1.0.0.
In fact, elsewhere the gulp docs explicitly state that glob ordering will be a new feature in gulp#4.0.0:
globs passed to gulp.src will be evaluated in order, which means this is possible gulp.src(['*.js', '!b*.js', 'bad.js']) (exclude every JS file that starts with a b except bad.js)
That means you could simply use to the current development version of gulp (gulpjs/gulp#4.0) and take advantage of the new feature. Note however that gulp 4.x is radically different from gulp 3.x when it comes to defining tasks.
One workaround would be to keep using gulp 3.x for tasks definitions, but use the newest version of vinyl-fs to create vinyl streams:
var vinylFs = require('vinyl-fs');
gulp.task('copy', function() {
return vinylFs.src(['client/*.js', '!client/b*.js', 'client/bad.js'])
.pipe(vinylFs.dest('public'));
});
And if you don't want to do that you can always use merge-stream to combine multiple streams into one stream:
var merge = require('merge-stream');
gulp.task('copy', function() {
return merge(gulp.src(['client/*.js', '!client/b*.js']),
gulp.src(['client/bad.js']))
.pipe(gulp.dest('public'));
});
I have a Gulp build process that runs through roughly 10 tasks, including browserify and watch. It currently builds a common-bundle.js, and common-libs.js. It uses browser-sync to give me sub-second rebuilds.
Now I want to also build a project that depends on the common project. I want to retain the live rebuilds of both common and this project so that I could work on both of them at the same time. I want to keep the build process itself as DRY as possible and reuse the tasks i created to build common.
For example, a sample task:
var config = require('../config');
gulp.task('styles', function () {
return gulp.src(config.styles.src) // if i could tell it to get config elsewhere...
...
I can't pass a parameter into each task to tell it, go run the task but use:
var config = require('../config').common;
vs.
var config = require('../config').projectA;
I don't think tasks can take parameters.
Is there a different way to structure this?
git/gist link would be highly appreciated.
For now I am trying this approach - each task js file has 2 tasks defined, but at least the logic of the task is reused. I still wish for something cleaner.
./gulp/task/style.js:
function styles(config){
return gulp.src(config.styles.src)
...
}
}
gulp.task('styles', function () {
styles(config.common);
});
gulp.task('stylesProject1', function () {
styles(config.project1);
});
devTask.js:
runSequence(['styles', 'stylesProject1], 'watch', callback);
I have seen this "destructing" syntax before but haven't ever used it. until now anyways. I want to pull in a react-router repo on github to handle my applications routing (making a single page app). but I noticed that it has this syntax
var { Route, RouteHandler, Link } = Router;
which is just a fancy way of writing
var Route = Router.Route
var RouteHandler = Router.RouteHandler
var Link = Router.Link
so my question is does anyone know if gulp will have any issues compiling this from jsx to javascript?
Do I need to install any additional dependencies for this syntax?
I have done some research but couldn't find anything conclusive. Thanks
The default gulp, yes. JSX syntax needs to be transpiled down to native js. Take a look at gulp-react to see how you can deal with this. Basically , it works in similar concept to other transpiled code (ie. coffeescript). Convert to native before piping along to the next task.
Edit
after seeing you're edit, it looks like you also need to convert the ES6. Take a look at the react browserify, it should help to get you going. Basically the concept is the same, compile jsx/es6 to native js. There's a section specific to the ES6 react components.
2nd Edit
Looks like gulp-react has an option to set to ES6. I think if you add this line, it will work.
.pipe(react({harmony: true}))
//full example
gulp.task('default', function () {
return gulp.src('template.jsx')
.pipe(react({harmony: true))
.pipe(gulp.dest('dist'));
});
Gulpfile.js
installed via npm install --save-dev gulp-load-plugins
var gulp = require('gulp');
// Require all tasks in gulp/tasks, including subfolders
require('require-dir')('./gulp/tasks', {
recurse: true
});
var $ = require('gulp-load-plugins')();
console.log($);
No matter where I declare it, the output will always be {}. I even tried with longer version having the options, still no luck
Using $.gulpif()
gives
TypeError: Object #<Object> has no method 'gulpif'
I even downloaded few starter packs from github but still getting same output. I'm kicking myself for moving from Grunt.
In the package.json, the plugin is saved as "gulp-if": "^1.2.5"
so, I had to change the code $.gulpif() to $.if() since the plugin will strip the names by below logic
var pattern = arrayify(options.pattern || ['gulp-*', 'gulp.*']);
var replaceString = options.replaceString || /^gulp(-|\.)/;
name.replace(replaceString, '');
A silly mistake which took 4 hours of my time.
P.S: I don't think it'll load any plugins without the prefix gulp in it's name.