npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

gulp-block-head

v1.3.0

Published

Simple, fast tool to filter SFC style files into seperate components

Downloads

17

Readme

gulp-block-head

Simple, fast tool to filter Single-File-Component style files into separate components.

This component was written out of frustration at the number of SFC supporting tools out there, none of which were simple, fast and unopinionated.

var blockHead = require('gulp-block-head');
var gulp = require('gulp');

gulp('./**/*.vue')
	.pipe(blockHead({
		// Wrap `<script component>` in Vue.component
		'script#component': contents => `Vue.component(${contents});`,

		// Accept regular script content with no attributes
		script: contents => contents,

		// Split CSS into its own file with a header
		css: {
			contents => `My CSS file\n${contents}`,
			name: (path, block) => `${path}.css`, // Append '.css' to end of input file name (e.g. myComponent.vue -> myComponent.vue.css)
		},
	}))

Tradeoffs

Since this module is designed to be fast and unopinionated some tradeoffs with processing have to be made:

  • File input is treated as lines, opening or closing block definitions are not supported
  • The remainder of the matching opening or closing block is discarded - block points must be on lines by themselves
  • By default any block items need to the very first things on their lines - putting a closing block mid-line will be ignored

The idea here is that we don't waste time throwing source code though gigantic XML processors to detect opening and closing sections. We just parse the files and splice the bits we're interested in.

Debugging

This module uses the debug module. Simply set DEBUG=block-head (or any other compatible inclusion expression) to show output.

DEBUG=block-head gulp build

Examples

Given a .vue file that looks like this:

<service singleton option="value">
module.exports = { ... };
</service>

<component>
module.exports = {
	methods: {
		doSomething() {
			// ...
		}
	},
};
</component>

<template>
	<div class="card">
		<div class="card-header">
			<h2>Test unit</h2>
		</div>
		<div class="card-body">
			Hello World
		</div>
	</div>
</div>

You can split the above .vue file using a config such as:

gulp.task('build.vue', ['load:app'], ()=>
	gulp.src([
		'**/*.vue',
		'!dist/**/*', // Don't get stuck in a loop
		'!node_modules/**/*',
	])
	.pipe(sourcemaps.init())
	.pipe(blockHead({
		blocks: {
			component: { // Accept something that should be registered via Vue.component()
				sort: 9, // Add after templates
				name: path => `components/${fspath.basename(path, '.vue')}.js`,
				transform: (content, path) =>
					`Vue.component('${fspath.basename(path, '.vue')}', `
					+ _.trimEnd(content, ';')
						.replace('{', `{\n\ttemplate: Vue.template('${fspath.basename(path, '.vue')}'),`)
					+ ')'
			},
			service: { // Accept some code to store as a shared service
				sort: 1,
				name: path => `services/${fspath.basename(path, '.vue')}.js`,
				transform: (content, path, block) => // Pass all attrs as arguments to the Vue.service() handler
					_.isEmpty(block.attr)
					? `Vue.service('${fspath.basename(path, '.vue')}', ${_.trimEnd(content, ';')});`
					: `Vue.service('${fspath.basename(path, '.vue')}', ${_.trimEnd(content, ';')}, ${JSON.stringify(block.attr)});`
			},
			script: { // Just dump the code inline
				sort: 0,
				name: path => `scripts/${fspath.basename(path, '.vue')}.js`,
				transform: content => content,
			},
			template: { // Wrap the HTML in a call to `Vue.template(id, html)`
				sort: 5,
				name: path => `templates/${fspath.basename(path, '.vue')}.js`,
				transform: (content, path) => `Vue.template('${fspath.basename(path, '.vue')}', \`${_.trimEnd(content, ';').replace(/\`/g, '\\`')}\`);`,
			},
		},
	}))
	.pipe(replace(/\s*module.exports =\s*/, '')) // Remove syntactic sugar
	.pipe(babel({
		presets: ['@babel/env'],
	}))
	.pipe(concat('app.js'))
	.pipe(uglify())
	.pipe(sourcemaps.write('.'))
	.pipe(gulp.dest('./dist'))

Notes:

  • In the above we assume that Vue.template(id, [html]) exists and provides a simple caching template store. You could alternatively dump your HTML into seperate files and deal with it that way
  • Likewise Vue.service(id, [object], [settings]) provides a caching service for objects, with additional options. Options are provided within a tag as attributes

API

This plugin exports a single Gulp / Vinyl compatible stream transformer accepting a settings object.

Each block definition accepts the following properties:

| Key | Type | Default | Description | |------------------------|-------------------------|----------------------------------------------------|--------------------------------------------------| | blocks | Array or Object | {} | Definition of the blocks | | blocks.[].id | String | (derived from object key) | The ID of the block | | blocks.[].filter | function or boolean | false | Whether to accept the block, if this is a function its called as (path, block) | | blocks.[].name | Function | (path, block) => ${path}#${block.id}</code> | How to name the output file | | blocks.[].transform |Function | <code>(contents, path, block) => contents</code> | How to transform the contents of the output file | |blocks.[].matchStart|RegExp | ``^<${block.id}(\s*.+?\s*)?>$`` | The matching start of the block | |blocks.[].matchEnd |RegExp |/^</${block.id}>$/ | The matching end of the block | |blocks.[].sort |Functionor any |0 | Where to output this block, if this is a function its called as(path, block)| |default |BooleanorObject |false | Whether to handle files when no blocks are found | |default.name |Function | | Optional renamer for default resources | |default.transform |Function | | Optional transformer for default resources | |default.include |Function | <code>(path) => true</code> | Determine whether to use the file in the output. If false no more processing is done. Applies only to thedefaultblock | |backpressure |Boolean, Numberor"warn"|"warn" | How to handle backpressure when buffering into a Vinyl stream.false= Ignore and continue silently,true- raise an error and exit,Number- wait this number of milliseconds and try again,"warn"- Print a warning but continue | |lineFeed |String |os.EOL` | Line feed character for this OS |

Notes:

  • The blocks definitions can be in the form of an object or an array
  • The default ID is used when no matches are found within the file
  • A decision whether the file output should be included at all can be set with the include function within the default block
  • The path parameter within name and transform functions is the original path of the file, not the rewritten one
  • Tag attributes are available as block.attr. Single attributes default to true: <block attr1 attr2="value2"> becomes {attr1: true, attr2: 'value2'}

BlockHead.import(files, options)

In addition to a Gulp adpater this module also provides the shorthand import() method which allows inline inclusion of JS files split into blocks.

This function will attempt to read then given files (which can be a single path, array or any valid gulp.src() glob), extract the given blocks and run them with a context. This is designed to be as close as possible to the import syntax.

var blockHead = require('gulp-block-head');


// Read the given HTML file and run all scripts specified in the 'script' blocks - this will execute in the current context
blockHead.import('./test/data/script.html', 'script')
	.then(()=> ...)


// Read the given HTML file and run all scripts specified in the 'script', 'include' and 'import' blocks - passing in a custom sandbox context
blockHead.import('./test/data/script.html', {
	blocks: ['script', 'include', 'import'],
	sandbox: {foo: 'Foo!'},
})
	.then(()=> ...)

This function supports the following options:

| Key | Type | Default | Description | |-----------|-------------------------------|-------------|--------------------------------------------------------------------------------| | blocks | String, Array or Object | "backend" | The blocks to process, see the notes below for more details | | src | Object | {} | Options to pass to gulp.src() when processing the file input | | sandbox | Boolean or Object | false | The sandbox to run the code in, if boolean false the current context is used |

Notes:

  • If blocks is a single string or array of strings the transform function is constructed automatically, if its an object the transform is ignored and a full BlockHead spec must be specified instead
  • If sandbox === false the script will have access to all objects in the current scope, including any declared globals
  • Passing a single string or array to the options parameter will assume setting of the blocks property