Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
gulp-inject
Advanced tools
A javascript, stylesheet and webcomponent injection plugin for Gulp, i.e. inject file references into your index.html
I don't have enough time to maintain this plugin as I would want to, so I'm looking for people who want to help out and be contributors/repository admins.
Contact me! See package.json
for contact information.
A stylesheet, javascript and webcomponent reference injection plugin for gulp. No more manual editing of your index.html!
<head>
and some into <body>
transform
function with default fallbackgulp-inject
takes a stream of source files, transforms each file to a string and injects each transformed string into placeholders in the target stream files. See Basic usage and More examples below.
Default transforms and placeholders exists for injecting files into html
, jade
, pug
, jsx
, less
, slm
, haml
and sass
/ scss
files.
Install gulp-inject
as a development dependency:
npm install --save-dev gulp-inject
The target file src/index.html
:
Each pair of comments are the injection placeholders (aka. tags, see options.starttag
and options.endtag
).
<!DOCTYPE html>
<html>
<head>
<title>My index</title>
<!-- inject:css -->
<!-- endinject -->
</head>
<body>
<!-- inject:js -->
<!-- endinject -->
</body>
</html>
The gulpfile.js
:
var gulp = require('gulp');
var inject = require('gulp-inject');
gulp.task('index', function () {
var target = gulp.src('./src/index.html');
// It's not necessary to read the files (will speed up things), we're only after their paths:
var sources = gulp.src(['./src/**/*.js', './src/**/*.css'], {read: false});
return target.pipe(inject(sources))
.pipe(gulp.dest('./src'));
});
src/index.html
after running gulp index
:
<!DOCTYPE html>
<html>
<head>
<title>My index</title>
<!-- inject:css -->
<link rel="stylesheet" href="/src/style1.css">
<link rel="stylesheet" href="/src/style2.css">
<!-- endinject -->
</head>
<body>
<!-- inject:js -->
<script src="/src/lib1.js"></script>
<script src="/src/lib2.js"></script>
<!-- endinject -->
</body>
</html>
By default the injected file paths are relative to each source file's cwd
(see options.ignorePath
). If options.relative
is set to true
each injected path will be relative to each target file's directory instead.
Project structure:
└── src
├── module
│ ├── module.js
│ └── module.html
└── app
├── main.js
└── index.html
src/app/index.html
:
<!DOCTYPE html>
<html>
<head>
<title>My Index</title>
</head>
<body>
<h1>Home</h1>
<!-- inject:js -->
<!-- endinject -->
</body>
</html>
src/module/module.html
:
<!DOCTYPE html>
<html>
<head>
<title>Module</title>
</head>
<body>
<h1>Module</h1>
<!-- inject:js -->
<!-- endinject -->
</body>
</html>
gulpfile.js
:
var inject = require('gulp-inject');
gulp.src('./src/**/*.html')
.pipe(inject(gulp.src('./src/**/*.js', {read: false}), {relative: true}))
.pipe(gulp.dest('./src'));
Resulting src/app/index.html
:
<!DOCTYPE html>
<html>
<head>
<title>My Index</title>
</head>
<body>
<h1>Home</h1>
<!-- inject:js -->
<script src="main.js"></script>
<script src="../module/module.js"></script>
<!-- endinject -->
</body>
</html>
Resulting src/module/module.html
:
<!DOCTYPE html>
<html>
<head>
<title>Module</title>
</head>
<body>
<h1>Home</h1>
<!-- inject:js -->
<script src="../app/main.js"></script>
<script src="module.js"></script>
<!-- endinject -->
</body>
</html>
This example demonstrates how to inject files from multiple different streams into the same injection placeholder.
Install event-stream
with: npm install --save-dev event-stream
and use its merge
function.
Code:
var es = require('event-stream'),
inject = require('gulp-inject'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify');
// Concatenate vendor scripts
var vendorStream = gulp.src(['./src/vendors/*.js'])
.pipe(concat('vendors.js'))
.pipe(gulp.dest('./dist'));
// Concatenate AND minify app sources
var appStream = gulp.src(['./src/app/*.js'])
.pipe(concat('app.js'))
.pipe(uglify())
.pipe(gulp.dest('./dist'));
gulp.src('./src/index.html')
.pipe(inject(es.merge(vendorStream, appStream)))
.pipe(gulp.dest('./dist'));
Use stream-series
.
Code:
var series = require('stream-series'),
inject = require('gulp-inject');
var vendorStream = gulp.src(['./src/vendors/*.js'], {read: false});
var appStream = gulp.src(['./src/app/*.js'], {read: false});
gulp.src('./src/index.html')
.pipe(inject(series(vendorStream, appStream))) // This will always inject vendor files before app files
.pipe(gulp.dest('./dist'));
<head>
and some into <body>
gulp-inject
's starttag
option.gulpfile.js
:
var inject = require('gulp-inject');
gulp.src('./src/index.html')
.pipe(inject(gulp.src('./src/importantFile.js', {read: false}), {starttag: '<!-- inject:head:{{ext}} -->'}))
.pipe(inject(gulp.src(['./src/*.js', '!./src/importantFile.js'], {read: false})))
.pipe(gulp.dest('./dist'));
And in your ./src/index.html
:
<!DOCTYPE html>
<html>
<head>
<title>My index</title>
<!-- inject:head:js -->
<!-- only importantFile.js will be injected here -->
<!-- endinject -->
</head>
<body>
<!-- inject:js -->
<!-- the rest of the *.js files will be injected here -->
<!-- endinject -->
</body>
</html>
gulp-inject
's name
option.gulpfile.js
:
var inject = require('gulp-inject');
gulp.src('./src/index.html')
.pipe(inject(gulp.src('./src/importantFile.js', {read: false}), {name: 'head'}))
.pipe(inject(gulp.src(['./src/*.js', '!./src/importantFile.js'], {read: false})))
.pipe(gulp.dest('./dist'));
And in your ./src/index.html
:
<!DOCTYPE html>
<html>
<head>
<title>My index</title>
<!-- head:js -->
<!-- only importantFile.js will be injected here -->
<!-- endinject -->
</head>
<body>
<!-- inject:js -->
<!-- the rest of the *.js files will be injected here -->
<!-- endinject -->
</body>
</html>
If you use Bower for frontend dependencies I recommend using main-bower-files
and injecting them as well.
gulpfile.js
:
var bowerFiles = require('main-bower-files'),
inject = require('gulp-inject'),
stylus = require('gulp-stylus'),
es = require('event-stream');
var cssFiles = gulp.src('./src/**/*.styl')
.pipe(stylus())
.pipe(gulp.dest('./build'));
gulp.src('./src/index.html')
.pipe(inject(gulp.src(bowerFiles(), {read: false}), {name: 'bower'}))
.pipe(inject(es.merge(
cssFiles,
gulp.src('./src/app/**/*.js', {read: false})
)))
.pipe(gulp.dest('./build'));
src/index.html
:
<!DOCTYPE html>
<html>
<head>
<title>My index</title>
<!-- bower:css -->
<!-- bower installed css files will go here... -->
<!-- endinject -->
<!-- inject:css -->
<!-- built css files will go here... -->
<!-- endinject -->
</head>
<body>
<!-- bower:js -->
<!-- bower installed scripts will go here... -->
<!-- endinject -->
<!-- inject:js -->
<!-- app scripts will go here... -->
<!-- endinject -->
</body>
</html>
Note remember to mount ./bower_components
, ./build
and ./src/app
as static resources in your server to make this work.
If you're writing an AngularJS application and follow Google's Angular APP Structure Recommendations, which I think you should, it's important that the script files are injected in the correct order to avoid module instantiation problems like Uncaught Error: [$injector:modulerr]
.
To do this you can use gulp-angular-filesort
together with gulp-inject
like so:
var angularFilesort = require('gulp-angular-filesort'),
inject = require('gulp-inject');
gulp.src('./src/index.html')
.pipe(inject(
gulp.src('./src/app/**/*.js') // gulp-angular-filesort depends on file contents, so don't use {read: false} here
.pipe(angularFilesort())
))
.pipe(gulp.dest('./build'));
You can customize gulp-inject
further by using the transform
function option, e.g. by injecting files into a json-file.
Code:
gulp.src('./files.json')
.pipe(inject(gulp.src(['./src/*.js', './src/*.css', './src/*.html'], {read: false}), {
starttag: '"{{ext}}": [',
endtag: ']',
transform: function (filepath, file, i, length) {
return ' "' + filepath + '"' + (i + 1 < length ? ',' : '');
}
}))
.pipe(gulp.dest('./'));
Initial contents of files.json
:
{
"js": [
],
"css": [
],
"html": [
]
}
transform
function with default fallbackThe default transform
function is available to use e.g. as a default fallback.
Used here to inject Word documents as <a>
tags below:
index.html
:
<!DOCTYPE html>
<html>
<head>
<title>My documents</title>
</head>
<body>
<h1>Documents</h1>
<ul>
<!-- inject:docx -->
<!-- endinject -->
</ul>
<!-- inject:js -->
<!-- endinject -->
</body>
</html>
gulpfile.js
:
var inject = require('gulp-inject');
gulp.src('./index.html')
.pipe(inject(
gulp.src(['./*.js', './docs/*.docx'], {read: false}), {
transform: function (filepath) {
if (filepath.slice(-5) === '.docx') {
return '<li><a href="' + filepath + '">' + filepath + '</a></li>';
}
// Use the default transform as fallback:
return inject.transform.apply(inject.transform, arguments);
}
}
))
.pipe(gulp.dest('./'));
Resulting index.html
:
<!DOCTYPE html>
<html>
<head>
<title>My documents</title>
</head>
<body>
<h1>Documents</h1>
<ul>
<!-- inject:docx -->
<li><a href="/docs/document1.docx"></a></li>
<li><a href="/docs/document2.docx"></a></li>
<!-- endinject -->
</ul>
<!-- inject:js -->
<script src="/lib1.js"></script>
<script src="/lib2.js"></script>
<!-- endinject -->
</body>
</html>
Code:
gulp.src('./bower.json')
.pipe(inject(gulp.src(['./dist/app.min.js', './dist/app.min.css'], {read: false}), {
starttag: '"main": [',
endtag: ']',
transform: function (filepath, file, i, length) {
return ' "' + filepath + '"' + (i + 1 < length ? ',' : '');
}
}))
.pipe(gulp.dest('./'));
Code:
gulp.src('./karma.conf.js')
.pipe(inject(gulp.src(['./src/**/*.js'], {read: false}), {
starttag: 'files: [',
endtag: ']',
transform: function (filepath, file, i, length) {
return ' "' + filepath + '"' + (i + 1 < length ? ',' : '');
}
}))
.pipe(gulp.dest('./'));
In order to inject files contents you have to provide custom transform
function, that will return file contents as string. You also have to omit {read: false}
option of gulp.src
in this case. Example below shows how to inject contents of html partials into head of index.html
:
Code:
gulp.src('./src/index.html')
.pipe(inject(gulp.src(['./src/partials/head/*.html']), {
starttag: '<!-- inject:head:{{ext}} -->',
transform: function (filePath, file) {
// return file contents as string
return file.contents.toString('utf8')
}
}))
.pipe(gulp.dest('./dest'));
And in your ./src/index.html
:
<!DOCTYPE html>
<html>
<head>
<title>My index</title>
<!-- inject:head:html -->
<!-- contents of html partials will be injected here -->
<!-- endinject -->
</head>
<body>
</body>
</html>
In order to inject files based on file path you have to provide custom starttag
which includes {{path}}
. Additionally, in order to inject file contents include transform
function, that will return file contents as string. You also have to omit {read: false}
option of gulp.src
in this case. Path can be either absolute, or relative in which case you should set [options.relative
] to true. Example below shows how to inject contents of html partials into index.html
:
Code:
gulp.src('./src/index.html')
.pipe(inject(gulp.src(['./src/partials/head/*.html']), {
starttag: '<!-- inject:{{path}} -->',
relative: true,
transform: function (filePath, file) {
// return file contents as string
return file.contents.toString('utf8')
}
}))
.pipe(gulp.dest('./dest'));
And in your ./src/index.html
:
<!DOCTYPE html>
<html>
<head>
<title>My index</title>
<!-- inject:path/to/your/file.ext -->
<!-- contents of html partials will be injected here -->
<!-- endinject -->
</head>
<body>
</body>
</html>
Parameter: sources
Type: Stream
Provide a Vinyl File Stream as input to inject
, see examples above.
Parameter: options
Type: Object
For available options see Options
Type: String
or Array
Default: NULL
A path or paths that should be removed from each injected file path.
This could also be solved by setting the cwd
option for your gulp.src
streams, each source file's cwd
is automatically removed from its path before injection (if not options.relative
is set to true
, see below).
Type: Boolean
Default: false
If set to true
paths for the injected files will be relative to each target file, this also means that each source file's cwd
is not necessary to remove from its path.
Type: String
Default: NULL
A path that should be prefixed to each injected file path.
Type: String
Default: NULL
A path that should be suffixed to each injected file path.
Type: Boolean
Default: !options.relative
The root slash is automatically added at the beginning of the path ('/'), or removed if set to false
.
Type: String
Default: "inject"
Used in the default start and end tags below.
Type: Boolean
Default: false
When true
the start and end tags will be removed when injecting files.
Type: Boolean
Default: false
When true
all tags without corresponding files will be emptied.
Warning this has the potential issue of emptying more than expected.
Type: String
|Function(targetExt, sourceExt)
Params (if function):
targetExt
- The file extension of the target filesourceExt
- The file extension of source filePurpose:
Used to dynamically set starting placeholder tag depending on file extensions.
In the provided string, or the string returned from the given function, the string {{ext}}
is replaced with the source file extension name, e.g. "css", "js" or "html". {{name}}
will be replaced by options.name
. {{path}}
will be replaced by path to source file (when used together with [options.relative
] it will allow relative path to source file.
A function dependent on target file type and source file type that returns:
<!-- {{name}}:{{ext}} -->
-# {{name}}:{{ext}}
//- {{name}}:{{ext}}
//- {{name}}:{{ext}}
{/* {{name}}:{{ext}} */}
/ {{name}}:{{ext}}
/* {{name}}:{{ext}} */
/* {{name}}:{{ext}} */
Type: String
|Function(targetExt, sourceExt)
Params (if function):
targetExt
- The file extension of the target filesourceExt
- The file extension of source filePurpose:
Used to dynamically set ending placeholder tag depending on file extensions.
In the provided string, or the string returned from the given function, the string {{ext}}
is replaced with the source file extension name, e.g. "css", "js" or "html". {{name}}
will be replaced by options.name
. {{path}}
will be replaced by path to source file.
A function dependent on target file type and source file type that returns:
<!-- endinject -->
-# endinject
//- endinject
//- endinject
{/* endinject */}
/ endinject
/* endinject */
/* endinject */
Type: Function(filepath, file, index, length, targetFile)
Params:
filepath
- The "unixified" path to the file with any ignorePath
's removed, addPrefix
and addSuffix
addedfile
- The File object to inject given from gulp.src
index
- 0-based file indexlength
- Total number of files to inject for the current file extensiontargetFile
- The target file to inject intoPurpose:
Used to generate the content to inject for each file.
A function dependent on target file type and source file type that returns:
Injecting into html
<link rel="stylesheet" href="<filename>.css">
<script src="<filename>.js"></script>
<script type="text/coffeescript" src="<filename>.coffee"></script>
<link rel="import" href="<filename>.html">
<img src="<filename>.png">
<img src="<filename>.gif">
<img src="<filename>.jpg">
<img src="<filename>.jpeg">
If options.selfClosingTag
is true
the default transformer above will make the <link>
and <img>
tags self close, i.e: <link ... />
and <img ... />
respectively.
Injecting into jsx
The same as for injecting into html
above with options.selfClosingTag
set to true
.
Injecting into jade
link(rel="stylesheet", href="<filename>.css")
script(src="<filename>.js")
script(type="text/coffeescript", src="<filename>.coffee")
link(rel="import", href="<filename>.html")
img(src="<filename>.png")
img(src="<filename>.gif")
img(src="<filename>.jpg")
img(src="<filename>.jpeg")
Injecting into pug
link(rel="stylesheet", href="<filename>.css")
script(src="<filename>.js")
script(type="text/coffeescript", src="<filename>.coffee")
link(rel="import", href="<filename>.html")
img(src="<filename>.png")
img(src="<filename>.gif")
img(src="<filename>.jpg")
img(src="<filename>.jpeg")
Injecting into slm
link rel="stylesheet" href="<filename>.css"
script src="<filename>.js"
script type="text/coffeescript" src="<filename>.coffee"
link rel="import" href="<filename>.html"
img src="<filename>.png"
img src="<filename>.gif"
img src="<filename>.jpg"
img src="<filename>.jpeg"
Injecting into haml
%link{rel:"stylesheet", href:"<filename>.css"}
%script{src:"<filename>.js"}
%script{type:"text/coffeescript", src:"<filename>.coffee"}
%link{rel:"import", href:"<filename>.html"}
%img{src:"<filename>.png"}
%img{src:"<filename>.gif"}
%img{src:"<filename>.jpg"}
%img{src:"<filename>.jpeg"}
Injecting into less
@import "<filename>.css";
@import "<filename>.less";
Injecting into scss
@import "<filename>.css";
@import "<filename>.scss";
@import "<filename>.sass";
Injecting into sass
@import "<filename>.css"
@import "<filename>.sass"
@import "<filename>.scss"
Type: Boolean
Default: false
Affects the default options.transform
function, see above.
Type: Boolean
Default: false
Lower the verbosity by setting this to true, suppressing the logging of successful injections.
DEPRECATED!
Deprecated since v.1.0
. Use gulp-file
instead:
var gulp = require('gulp');
var file = require('gulp-file');
var inject = require('gulp-inject');
file('index.html', '<html><head></head></html>')
.pipe(inject(gulp.src(['./src/app/**/*.js']), {
starttag: '<head>',
endtag: '</head>'
}))
.pipe(gulp.dest('./dest'));
DEPRECATED!
Deprecated since v.1.0
. Use sort-stream
instead:
var gulp = require('gulp');
var sort = require('sort-stream');
var inject = require('gulp-inject');
gulp.src('index.html')
.pipe(inject(
gulp.src(['./src/app/**/*.js'])
.pipe(sort(function (a, b) {
// Sort condition here...
}))
))
.pipe(gulp.dest('./dest'));
The default transform function is exposed in the public API.
For more details see the code with tests.
The default transform function for files into html
, or other file types not jade
, pug
, jsx
, slm
, less
, scss
, sass
or haml
.
The default transform function for files into jade
.
The default transform function for files into pug
.
The default transform function for files into jsx
.
The default transform function for files into slm
.
The default transform function for files into haml
.
The default transform function for files into less
.
The default transform function for files into sass
.
The default transform function for files into scss
.
FAQs
A javascript, stylesheet and webcomponent injection plugin for Gulp, i.e. inject file references into your index.html
The npm package gulp-inject receives a total of 31,885 weekly downloads. As such, gulp-inject popularity was classified as popular.
We found that gulp-inject demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.