
Security News
Browserslist-rs Gets Major Refactor, Cutting Binary Size by Over 1MB
Browserslist-rs now uses static data to reduce binary size by over 1MB, improving memory use and performance for Rust-based frontend tools.
reduce-web-component
Advanced tools
Features
browserify
and depsify
to pack scripts and styles into common shared bundles.watchify2
to watch file changes, addition and deletion.postcss
to preprocess styles by default.Suppose we put pages under the directory /path/to/src/page
,
and other components under /path/to/src/node_modules
.
A page or component may have a style entry as well as a script entry.
For simplicity, entries are named as index.[js|css]
if present.
There are two pages (hello
and hi
), as well as two components (world
, earth
).
The hello
page will present the world
component (both scripts and styles needed).
We can do this by adding require('world')
in hello/index.js
,
and @import "world";
in hello/index.css
.
However, if world
is no longer needed,
we have to remove both require('world')
and @import "world"
,
which is really cumbersome.
So, we decide that if the script entry is require
d,
the corresponding style entry should also be @import
ed.
In such cases, we say the component is required.
This is achieved by adding style dependencies according to script dependencies.
Eventually, we want scripts required by all pages to be packed into /path/to/build/bundle.js
,
and styles into /path/to/build/bundle.css
.
We can use this package to do that.
The hello
page
page/hello/index.js
)module.exports = 'hello, ' + require('world')
page/hello/index.css
).hello {}
The hi
page
page/hi/index.js
)module.exports = 'hi, ' + require('earth')
null
)The world
component
node_modules/world/index.js
)module.exports = 'world'
node_modules/world/index.css
).world {
color: red;
}
The earth
component
node_modules/earth/index.js
)module.exports = 'earth'
node_modules/earth/index.css
).earth {
color: blue;
}
The original dependency graph looks like:
The dependency graph we want for bundling should look like:
NOTE
As hi
requires earth
and earth
is shipped with styles,
hi
will need styles at last.
So a virtual hi/index.css
is created (but not written into disk).
We run the following script to bundle js and css:
'use strict'
const path = require('path')
const reduce = require('reduce-web-component')
const options = {
getStyle: function (jsFile) {
return path.dirname(jsFile) + '/index.css'
},
reduce: {
basedir: path.resolve(__dirname, 'src'),
},
on: {
log: console.log.bind(console),
error: function (err) {
console.error(err.stack)
},
'reduce.end': function (bytes, duration) {
console.log(
'[%s done] %d bytes written (%d seconds)',
this._type, bytes, (duration / 1000).toFixed(2)
)
},
},
js: {
entries: 'page/**/index.js',
bundleOptions: 'bundle.js',
dest: 'build',
},
css: {
// No need to specify entries,
// because we have done that implicitly by setting getStyle.
// entries: 'page/**/index.css',
bundleOptions: 'bundle.css',
dest: 'build',
},
}
reduce.bundle(options).then(() => console.log('DONE'))
Besides hello/index.css
and world/index.css
,
earth/index.css
will also be included in bundle.css
.
const reduce = require('reduce-web-component')
// pack
reduce.bundle(options).then(() => {})
// watch mode
reduce.watch(options).on('done', () => {})
To work with gulp
:
const gulp = require('gulp')
const reduce = require('reduce-web-component')
gulp.task('build', () => {
return reduce.bundle(options)
})
gulp.task('watch', function (cb) {
reduce.watch(options)
.on('close', cb)
.on('done', () => console.log('-'.repeat(40)))
})
Check the configure file.
Scripts are bundled with browserify
.
So, plugins and transforms can be applied during the build process.
Check browserify-handbook
for more information.
Styles are preprocessed with postcss
.
Check reduce-css-postcss
to see the default processors.
depsify
is used to bundle styles,
so that styles can be packed into common shared multiple bundles.
Options for both JS and CSS bundling are configurable.
Check reduce-js
and reduce-css
for the following options:
entries
. Type: String
, Array
. Optional Globs to locate entries.reduce
. Type: Object
. Options passed to browserify
or depsify
.bundleOptions
. Type: Object
. Options passed to common-bundle
.dest
. Type: String
, Array
. Options passed to [b.dest
].watch
. Type: Object
. Options passed to watchify2
.Other options:
on
. Type: Object
. Listeners to be added to the bundler instance.plugin
. Plugins to process the vinyl stream. They are just like gulp plugins.Example:
{
js: {
entries: 'page/**/index.js',
reduce: { basedir: '/path/to/src' },
bundleOptions: {
groups: 'page/**/index.js',
common: 'common.js',
},
watch: {
ignoreWatch: ['**/node_modules/**'],
entryGlob: 'page/**/index.js',
},
on: {
'common.map': o => {},
error: console.log,
}
},
css: {
entries: 'page/**/index.css',
reduce: { basedir: '/path/to/src' },
bundleOptions: { groups: 'page/**/index.css', common: 'common.css' },
watch: {
ignoreWatch: ['**/node_modules/**'],
entryGlob: 'page/**/index.css',
},
on: {
error: console.log,
}
},
}
Meanwhile, we have:
getStyle
: bind JS and CSS together so that when js is required, the corresponding css will also be imported implicitly by the dependant's css.{
getStyle: jsFile => {
return path.dirname(jsFile) + '/index.css'
},
js: {},
css: {},
}
Suppose there are /path/to/component/x/index.js
and /path/to/component/y/index.js
,
and their binding CSS are /path/to/component/x/index.css
and /path/to/component/y/index.css
respectively.
If we require('../y')
in x/index.js
,
then CSS will be bundled as if there is @external "../y";
in x/index.css
.
Common options for both options.js
and options.css
could also be specified as properties of options
:
{
// common options
reduce: { basedir: '/path/to/src' },
on: {
error: console.log,
},
js: {
entries: 'page/**/index.js',
bundleOptions: {
groups: 'page/**/index.js',
common: 'common.js',
},
watch: {
ignoreWatch: ['**/node_modules/**'],
entryGlob: 'page/**/index.js',
},
on: {
'common.map': o => {},
}
},
css: {
entries: 'page/**/index.css',
bundleOptions: { groups: 'page/**/index.css', common: 'common.css' },
watch: {
ignoreWatch: ['**/node_modules/**'],
entryGlob: 'page/**/index.css',
},
},
}
Environment-specific options are possible:
{
reduce: { basedir: '/path/to/src' },
on: {
error: console.log,
},
js: {
entries: 'page/**/index.js',
bundleOptions: {
groups: 'page/**/index.js',
common: 'common.js',
},
watch: {
ignoreWatch: ['**/node_modules/**'],
entryGlob: 'page/**/index.js',
},
on: {
'common.map': o => {},
}
},
css: {
entries: 'page/**/index.css',
bundleOptions: { groups: 'page/**/index.css', common: 'common.css' },
watch: {
ignoreWatch: ['**/node_modules/**'],
entryGlob: 'page/**/index.css',
},
},
env: {
development: {
js: {
reduce: {
plugin: ['index-hashify', 'browserify-hmr']
},
}
},
production: {
js: {
plugin: 'gulp-uglify'
},
css: {
plugin: 'gulp-uglifycss'
}
},
}
}
FAQs
Pack js and css files in web components
The npm package reduce-web-component receives a total of 8 weekly downloads. As such, reduce-web-component popularity was classified as not popular.
We found that reduce-web-component demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 3 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
Browserslist-rs now uses static data to reduce binary size by over 1MB, improving memory use and performance for Rust-based frontend tools.
Research
Security News
Eight new malicious Firefox extensions impersonate games, steal OAuth tokens, hijack sessions, and exploit browser permissions to spy on users.
Security News
The official Go SDK for the Model Context Protocol is in development, with a stable, production-ready release expected by August 2025.