precaching a generated asset in Service Worker - javascript

I have some resources which are getting generated on runtime or on build for example scripts, CSS, etc.
The file format is something like this main.min.63716273681.js and similarly for other resources as well.
Unfortunately, I cannot use sw-precache library or anything integrated with my build.
How can I precache those resources, Is it possible to do it using regex?
Note: The question is about precaching the resource and resources are getting generated by AEM(Adobe experience manager)

install webpack-manifest-plugin and import at the top of your webpack config file
const ManifestPlugin = require('webpack-manifest-plugin');
use the below code in your webpack plugin section this will generate a file name asset-manifest.json with all the assets that are build by webpack
new ManifestPlugin({
fileName: 'asset-manifest.json',
publicPath: your public path here,
}),
it will generate file having content like below
// asset-manifest.json
{
"files": {
"about.js": "/static/js/about.bc816d03.chunk.js",
"about.js.map": "/static/js/about.bc816d03.chunk.js.map",
"dashboard.js": "/static/js/dashboard.f180c270.chunk.js",
"dashboard.js.map": "/static/js/dashboard.f180c270.chunk.js.map",
"homepage.js": "/static/js/homepage.4dd0316c.chunk.js",
"homepage.js.map": "/static/js/homepage.4dd0316c.chunk.js.map",
"login.js": "/static/js/login.1b8cf466.chunk.js",
"login.js.map": "/static/js/login.1b8cf466.chunk.js.map",
"logout.js": "/static/js/logout.ac3c5758.chunk.js",
"logout.js.map": "/static/js/logout.ac3c5758.chunk.js.map",
"main.css": "/static/css/main.977b6895.chunk.css",
"main.js": "/static/js/main.a65a1d5d.chunk.js",
"main.js.map": "/static/js/main.a65a1d5d.chunk.js.map",
"profile.js": "/static/js/profile.20ae3dae.chunk.js",
"profile.js.map": "/static/js/profile.20ae3dae.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.ad8b0a50.js",
"runtime-main.js.map": "/static/js/runtime-main.ad8b0a50.js.map",
"static/js/8.796ce7e3.chunk.js": "/static/js/8.796ce7e3.chunk.js",
"static/js/8.796ce7e3.chunk.js.map": "/static/js/8.796ce7e3.chunk.js.map",
"index.html": "/index.html",
"precache-manifest.e770a629726af82e25b547dd941bae89.js": "/precache-manifest.e770a629726af82e25b547dd941bae89.js",
"service-worker.js": "/service-worker.js",
"static/css/main.977b6895.chunk.css.map": "/static/css/main.977b6895.chunk.css.map",
"static/js/8.796ce7e3.chunk.js.LICENSE.txt": "/static/js/8.796ce7e3.chunk.js.LICENSE.txt",
"static/media/arvidsson.jpg": "/static/media/arvidsson.4d6f8e0d.jpg",
"static/media/logo.jpg": "/static/media/logo.8caa15b8.jpg",
"static/media/pekka.jpg": "/static/media/pekka.1eab475c.jpg"
},
"entrypoints": [
"static/js/runtime-main.ad8b0a50.js",
"static/js/8.796ce7e3.chunk.js",
"static/css/main.977b6895.chunk.css",
"static/js/main.a65a1d5d.chunk.js"
]
}
you can read asset-manifest.json file and take the files object and iterate and check the key having .js in the end.
Hope this will answer your question.

Related

Webpack 5 IgnorePlugin - Not ignoring JS file from output on CSS files only?

I am trying to use the Webpack's IngorePlugin. I am using my Webpack file only to create a CSS file. On build, it outputs a JS file. But I don't want that. Tried ignoring JS files but still outputs it.
new webpack.IgnorePlugin(/^\.\/js\/(?!admin)/),
Outputs in the ROOT folder. So I want to disable all JS files from the output in the root folder. "admin" is the file being created.
How can I do this?
To properly answer your question, it'd be helpful if you posted a link to the full WP config file and an example of the file that's being processed.
Also, you mentioned you're only using WP to create a CSS file, does that mean you're just trying to use something like SASS, Stylus, Less, etc? If so, you could probably just set up a package.json script to compile your CSS without WP.
For example, if you have a .scss file, you could install node-sass, and create a simple Node script to compile what file you pass in as an arg.
bin/
- build-css.js
src/
- styles.sass
Within build-css.js
#!/usr/bin/env node
const { basename, resolve } = require('path');
const sass = require('node-sass');
const [...files] = process.argv.slice(2);
if (files.length) {
files.forEach((relativeFilePath) => {
const fileName = basename(relativeFilePath, '.scss');
sass.render(
{
file: resolve(__dirname, relativeFilePath),
outFile: resolve(__dirname, `./public/css/${fileName}.css`),
},
(err, result) => { console.log(err); }
);
});
}
else {
console.log('No files were provided to process');
}
Within package.json
"scripts": {
"build:css": "node ./bin/build-css.js"
}
The above has the benefit of giving you the control of how your files are processed at a more granular level, and you're only locked in to any SCSS changes, instead of Webpack and SCSS.
If you're using WP for it's file watching capabilities, you could instead wire up chokidar to run the new script when you change files.

Add a JavaScript file to webpack build without using Manifest

I have a plain webpack app, index.html, main.js, that builds just fine.
I also have a self contained javascript file iframe.js, to be added to 3rd party sites that will add an iframe container referencing the webpack app:
<iframe src="https://webpack-app-domain.com/index.html">
I would like the webpack build to process iframe.js with process.env substitutions of the sort:
<%= process.env.IFRAME_URL %>
and let babel convert it to ES5 javascript and minify the output for production, but I do NOT want iframe.js to be part of the Manifest nor other dependencies introduced into the script.
It is not a webpack "entry".
If I place it in the /static folder it will get deployed, unaltered, but I cannot then customise it with any process.env variables, nor transpile, nor minify it.
If I add it as a separate webpack "entry", it gets transpiled and minified, but it also gets wrapped in a manifest function call: webpackJsonp(), yet I need the javascript to be self-contained.
How can I process this javascript file with the webpack build to satisfy my requirements?
Edit: Thanks for your replies. I applied an inline transform with the CopyWebpackPlugin to achieve my desired outcome:
const UglifyJS = require('uglify-js')
const babel = require("babel-core")
...
new CopyWebpackPlugin([
{
from: 'src/iframe.js',
to: '',
transform(content, path) {
let js = content.toString('utf8')
js = js.replace(new RegExp("process.env.IFRAME_URL", 'g'), env.IFRAME_URL)
.replace(new RegExp("process.env.ROOT_API", 'g'), env.ROOT_API)
let t = babel.transform(js, {
presets: ["env"]
})
if (t.error) throw t.error
js = t.code
let min = UglifyJS.minify(js)
if (min.error) throw min.error
js = min.code.toString()
return Buffer.from(js)
},
},
])
I'm not sure if this is the most elegant way but it does the job. It's duplicating the plugin pipeline that's otherwise bypassed.
I fail to see where manifest.json relates to this question.
My answer: Use externals paired with a custom command for a separate webpack build. It's not uncommon to have more than one compilation step in a project.
If you are using package.json, then you could add this to the scripts section, and if you are using command line then just make shell script or something.
NODE_ENV=some_env webpack --config webpack.iframe.config.js --progress --colors -d --output-path 'assets' --display verbose
Then you're free to separate the dependency build from the project build, and include the results as an external in your main project.
Have you tried using using copy-webpack-plugin?
This way you would run your normal build in parallel to copying a single file.
You can use the transform method to replace the contents of the file for process.env.* and output it to the destination you want.
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
new CopyPlugin([
{
from: 'src/*.png',
to: 'dest/',
transform(content, path) {
return optimize(content);
},
},
]),
],
};

Webpack to simply compile a bunch of Pug templates to HTML

Im getting started with webpack but one thing I cannot for the life of me work out is how to take a folder (with possible nested folders), full of .pug templates, and simply compile them to static html and put them in the output folder, maintaining any nested folder structure for each output html file that was in the source templates folder...
I dont want to have to manually specify each individual .pug file, and I definitely dont want webpack to try and parse the .pugs into JS and then attempt to require/import any of the imgs/fonts etc in the pug files and then complain about it, Im just after a basic, static 1:1 compile, pug file in, html file out. Why is it so hard to do that?
Use pug-html-loader to convert .pug to .html file. Use file-loader to copy the file to desired location. Don't use html-loader as you don't want to process resources used by the generated file.
You will end up something like this in your loader rules (untested, webpack 1 syntax, you may need to tweak it for webpack 2)
{
test: /\.pug$/,
loaders: ['file-loader?name=[path][name].html', 'pug-html-loader?pretty&exports=false']
}
Next you need to require all your pug files in your entry file
function requireAll (r) { r.keys().forEach(r); }
requireAll(require.context('./', true, /\.pug$/));
This can be done very simply with only html-webpack-plugin and pug-loader.
webpack.config.js
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// No javascript entrypoint to evaluate. Let the plugin do the heavy lifting
entry: {},
// Translate Pug to HTML
module: { rules: [ { test: /\.pug$/, use: 'pug-loader' } ] },
// Save HTML to file
plugins: [ new HTMLWebpackPlugin({ template: './src/index.pug' }) ]
};
./src/index.pug
doctype html
html(land="en")
head
include path/to/another.pug
...
Got this information from https://extri.co/2017/05/23/using-htmlwebpackplugin-and-pug/ and you can also go further to import css and javascript as normally done with html-webpack-plugin.

Path aliases for imports in WebStorm

I use webpack path aliases for ES6 module loading.
E.g. If I define an alias for utils instead of something like
import Foo from "../../../utils/foo", I can do
import Foo from "utils/foo"
The problem is that once I start using aliases, WebStorm looses track of the import and I'm left with warnings and no auto-completion.
Is there a way to instruct WebStorm to use such aliases?
Yes, there is.
In fact, Webstorm can't automatically parse and apply Webpack config, but you can set up aliases the same way.
You just have to mark the parent folder of "utils" (in your example) as a resource root (right-click, mark directory as / resource root).
We just managed to do with the following structure :
/src
/A
/B
/C
We have A B and C folders declared as alias in Webpack.
And in Webstorm we marked "src" as "Resource Root".
And now we can simply import :
import A/path/to/any/file.js
instead of
import ../../../../../A/path/to/any/file.js
while still having Webstorm correctly parsing and indexing all code, link to files, autocompleting and so on ...
I managed to set up aliases for WebStorm 2017.2 within webpack like this:
For the record: in PHPSTORM, working with laravel mix, I managed to solve this by creating a webpack.config.js file separately like:
const path = require('path')
const webpack = require('webpack')
module.exports = {
...
resolve: {
extensions: ['.js', '.json', '.vue'],
alias: {
'~': path.resolve(__dirname, './resources/assets/js')
}
},
...
}
And then importing it in the webpack.mix.js like:
const config = require('./webpack.config')
...
mix.webpackConfig(config)
Make sure the webpack configuration file is pointed correctly in the configuration of the PhpStorm in: Settings > Languages & Frameworks > Javascript > Webpack
You can define custom paths, so WebStorm/PhpStorm can understand your aliases. But make sure, they are identical with your aliases. Create file in your root directory and call it something like this: webStorm.config.js (any js file will be ok). Then configure your paths inside:
System.config({
"paths": {
"components/*": "./src/components/*",
"core/*": "./src/core/*",
...
}
});
WebStorm/PhpStorm will recognize System as it's own module and will treat this file as configuration.
This is answered in a comment but to save people digging into comments and link only information, here it is:
As of WS2017.2 this will be done automatically. The information is here.
According to this, webstorm will automatically resolve aliases that are included within the webpack.config in the root of the project. If you have a custom structure and your webpack.config isn't in the root folder then go to Settings | Languages & Frameworks | JavaScript | Webpack and set the option to the config you require.
Note: Most setups have a base config which then call a dev or prod version. In order for this to work properly, you need to tell webstorm to use the dev one.
Not right now, We were also using path aliases for the files in our react project. The import names were shorter but we lost a lot on static checking of webstorm as well as completion features.
We later came up with a decision to reduce the code to only 3 levels of depth, as well a single level for the common parts. The path completion feature of webstom (ctrl + space) even helps reduce the typing overhead. The production build does not use longer names, so hardly makes any difference in final code.
I will suggest please reconsider your decision about aliases. You loose semantic meaning of modules coming from node_modules and your own code, as well as referencing the alias files again and again to make sense of your code, is a much bigger overhead.
add jsconfig.js on your project root
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["./src/*"]
}
}
}
In PHPStorm (using 2017.2 currently), I have not been able to get webpack configs to work properly in regards to aliases.
My fix involves using the "Directories" section of the main settings. I just had to mark each folder referenced by an alias as a sources root, then click the properties dropdown for each and specify the alias as a "Package prefix". This made everything link up for me.
Not sure if the Directories section exists in WebStorm, but if it does, this seems to be a fool-proof method for getting import aliases working.
For anyone struggling: path.resolve() must be called with "__dirname" first argument for Idea (Websorm) to be able to resolve the path correctly.
Will work for Idea (Websorm):
alias: {
'#someAlias': pathLib.resolve(__dirname, 'path/to/directory')
}
Will not work for Idea (Websorm) (while still being valid webpack alias):
alias: {
'#someAlias': pathLib.resolve('path/to/directory')
}
Webstorm can't read webpack.config if module.exports return a function.
For example
module.exports = function (webpackEnv) {
return {
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
...
}
}
Check your config file, maybe this cause you are a problem.
There is a lot of discussion here about Laravel Mix, so I'll leave this here to help out future readers. I solved this by creating a separate (fake) webpack config file which is only used by my IDE (PHPStorm).
1. Create a separate alias.js file (e.g. /webpack/alias.js)
const path = require('path');
const assets = path.join(__dirname,'..','resources','assets');
module.exports = {
'#js' : path.resolve(assets, 'js'),
'#c' : path.resolve(assets, 'js', 'components'),
'#errors' : path.resolve(assets, 'js', 'errors'),
'#utils' : path.resolve(assets, 'js', 'utils'),
'#store' : path.resolve(assets, 'js', 'store'),
'#api' : path.resolve(assets, 'js', 'api'),
'#less' : path.resolve(assets, 'less')
}
2. Require the alias.js file into webpack.mix.js
const mix = require('laravel-mix');
mix.alias(require('./webpack/alias'))
// ... The rest of your mix, e.g.
.js('app.js')
.vue()
.less('app.less');
3. Create the fake webpack config for your IDE (e.g. /webpack/ide.config.js)
Here, import the laravel-mix webpack config, plus your aliases, and any other config that the IDE might need help finding. Also include the prefixed ~ aliases for importing styles into your Vue components.
/*
|--------------------------------------------------------------------------
| A fake config file for PhpStorm to enable aliases
|--------------------------------------------------------------------------
|
| File > Settings... > Languages & Frameworks > Javascript > Webpack
|
| Select "Manually" and set the configuration file to this
|
*/
const path = require('path');
const mixConfig = require('./../node_modules/laravel-mix/setup/webpack.config')();
module.exports = {
...mixConfig,
resolve: {
alias: {
...require('./alias'),
'~#less' : path.resolve('#less'), // <--
},
...mixConfig.resolve
}
}
4. Set your IDE to use webpack/ide.config.js as your webpack config file.
Had the same problem on a new Laravel project with Jetstream. The webpack.config.js was present and correct. But PHPStorm still didn't recognize the # symbol as a resource root.
After opening the webpack config, I got a notification:
After Clicking on Trust project and run, the # symbol became recognized.
I know that this isn't the solution or use-case for everyone. But I still found it worthy to note on this post, because it helped me in my situation.
Using
laravel/framework:8.77.1
npm:8.3.0
node:v14.18.1

Simple solution to share modules loaded via NPM across multiple Browserify or Webpack bundles

Pulling my hair out here looking for a simple solution to share code, required via NPM, across multiple Browserify or Webpack bundles. Thinking, is there such a thing as a file "bridge"?
This isn't due to compile time (I'm aware of watchify) but rather the desire to extract out all of my vendor specific libs into vendor.js so to keep my app.js filesize down and to not crash the browser with massive sourcemaps. Plus, I find it way cleaner should the need to view the compiled js arise. And so:
// vendor.js
require('react');
require('lodash');
require('other-npm-module');
require('another-npm-module');
Its very important that the code be loaded from NPM as opposed to Bower, or saved into some 'vendor' directory in order to be imported via a relative path and identified via a shim. I'd like to keep every library reference pulled via NPM except for my actual application source.
In app.js I keep all of my sourcecode, and via the externals array, exclude vendor libraries listed above from compilation:
// app.js
var React = require('react');
var _ = require('lodash');
var Component = React.createClass()
// ...
And then in index.html, I require both files
// index.html
<script src='vendor.js'></script>
<script src='app.js'></script>
Using Browserify or Webpack, how can I make it so that app.js can "see" into those module loaded via npm? I'm aware of creating a bundle with externals and then referencing the direct file (in, say, node_modules) via an alias, but I'm hoping to find a solution that is more automatic and less "Require.js" like.
Basically, I'm wondering if it is possible to bridge the two so that app.js can look inside vendor.js in order to resolve dependencies. This seems like a simple, straightforward operation but I can't seem to find an answer anywhere on this wide, wide web.
Thanks!
Listing all the vendor files/modules and using CommonChunkPlugin is indeed the recommended way. This gets pretty tedious though, and error prone.
Consider these NPM modules: fastclick and mprogress. Since they have not adopted the CommonJS module format, you need to give webpack a hand, like this:
require('imports?define=>false!fastclick')(document.body);
require('mprogress/mprogress.min.css');
var Mprogress = require('mprogress/mprogress.min.js'),
Now assuming you would want both fastclick and mprogress in your vendor chunk, you would probably try this:
module.exports = {
entry: {
app: "./app.js",
vendor: ["fastclick", "mprogress", ...]
Alas, it doesn't work. You need to match the calls to require():
module.exports = {
entry: {
app: "./app.js",
vendor: [
"imports?define=>false!fastclick",
"mprogress/mprogress.min.css",
"mprogress/mprogress.min.js",
...]
It gets old, even with some resolve.alias trickery. Here is my workaround. CommonChunkPlugin lets you specify a callback that will return whether or not you want a module to be included in the vendor chunk. If your own source code is in a specific src directory, and the rest is in the node_modules directory, just reject the modules based on their path:
var node_modules_dir = path.join(__dirname, 'node_modules'),
app_dir = path.join(__dirname, 'src');
module.exports = {
entry: {
app: "./app.js",
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(
/* chunkName= */"vendor",
/* filename= */"vendor.bundle.js"
function (module, count) {
return module.resource && module.resource.indexOf(app_dir) === -1;
}
)
]
};
Where module.resource is the path to the module being considered. You could also do the opposite, and include only the module if it is inside node_modules_dir, i.e.:
return module.resource && module.resource.indexOf(node_modules_dir) === 0;
but in my situation, I'd rather say: "put everything that is not in my source source tree in a vendor chunk".
Hope that helps.
With webpack you'd use multiple entry points and the CommonChunkPlugin.
Taken from the webpack docs:
To split your app into 2 files, say app.js and vendor.js, you can require the vendor files in vendor.js. Then pass this name to the CommonChunkPlugin as shown below.
module.exports = {
entry: {
app: "./app.js",
vendor: ["jquery", "underscore", ...],
},
output: {
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(
/* chunkName= */"vendor",
/* filename= */"vendor.bundle.js"
)
]
};
This will remove all modules in the vendor chunk from the app chunk. The bundle.js will now contain just your app code, without any of it’s dependencies. These are in vendor.bundle.js.
In your HTML page load vendor.bundle.js before bundle.js.
<script src="vendor.bundle.js"></script>
<script src="bundle.js"></script>
// vendor anything coming from node_modules
minChunks: module => /node_modules/.test(module.resource)
Source: https://github.com/webpack/webpack/issues/2372#issuecomment-213149173

Categories

Resources