Direct conversion of small files (Base64)
Conduct the server on a large file and replace the path
likeness url-loader -> fallback
config.module
.rule('images')
.set('parser', {
dataUrlCondition: {
maxSize: 500 * 1024,
},
})
.set('generator', {
filename: 'img/[name].[hash:8].[ext]'
})
.end();
Related
I need to resolve the urls at runtime. I have configured it like this
experimental: {
renderBuiltUrl: (filename: string, { hostType, type }) => {
if (hostType === 'js') {
return { runtime: `window.__toDynamicUrl(${JSON.stringify(filename)})` };
}
return { relative: true }
}
}
The problem is when new js files are loaded dynamically (u load some nested route), they are added to index.html file like this i.e. not adding the dynamic path before assets
// index.html
<link rel="modulepreload" as="script" crossorigin="" href="/assets/myComponent.a2adaa03.js">
...
<script>
window.__toDynamicUrl = (file) => `_some_path_/spa/${file}`;
</script>
It depends on what problem you are solving...
Q: Do you want to generate a correct HTML file with your build (vite)?
A: Don't need to use realtime
experimental: {
renderBuiltUrl: (filename: string, { hostType, type }) => {
if (hostType === 'js') {
return `_some_path_/spa/${filename}`;
}
return { relative: true }
}
}
Q: Do you want to generate a correct HTML file in the external server?
A: https://vitejs.dev/guide/backend-integration.html
You can generate a manifest file
// vite.config.js
export default defineConfig({
build: {
// generate manifest.json in outDir
manifest: true, // <- add
rollupOptions: {
// overwrite default .html entry
input: '/path/to/main.js',
},
},
})
and use realtime
I have just created a new CRA app. In our organization we have a micro frontend framework which has certain requirements when it comes to the the asset file of each micro frontend app. CRA will by default, create a asset-manifest.json file.
https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/config/webpack.config.js#L656
Now I need to change this file to assets.json and make some structural changes as well. To achieve this I use CRACO and add the WebpackManifestPlugin.
const ManifestPlugin = require('webpack-manifest-plugin');
module.exports = {
webpack: {
plugins: {
// tried removing CRA definition for ManifestPlugin.
// It worked, but had no impact on my problem
// remove: ['ManifestPlugin'],
add: [
new ManifestPlugin({
fileName: 'assets.json',
generate: (seed, files, entrypoints) => {
const js = [],
css = [];
files.forEach((file) => {
if (file.path.endsWith('.js') && file.isInitial) {
js.push({ value: file.path, type: 'entry' });
}
if (file.path.endsWith('.css') && file.isInitial) {
css.push({ value: file.path, type: 'entry' });
}
});
return { js, css };
},
})
]
}
}
};
Whenever I build the application, my new assets.json file is generated as expected.
However, I can't get CRA, or webpack-dev-server I assume, to serve this file while I run my CRA app in development mode. It only resolves to the index.html file. I have looked through CRA source code and can't really find any relevant place where asset-manifest.json is mentioned.
So how do I get webpack-dev-server to serve my assets.json file?
You need to add the ManifestPlugin to webpack.plugins.remove array to receive only the configuration from WebpackManifestPlugin:
...
webpack: {
alias: {},
plugins: {
add: [
new WebpackManifestPlugin(webpackManifestConfig)
],
remove: [
"ManifestPlugin"
],
},
configure: (webpackConfig, { env, paths }) => { return webpackConfig; }
},
...
I'm trying to lazy load routes in a Vue 2 application following the guides but webpack is not creating the chunks.
In my router file
const Home = () => import(/* webpackChunkName: "Home" */'#/features/titles/views/Home.vue');
My vue config's file is already removing the prefetch - and preload - plugin (as suggested here)
config.plugins.delete('prefetch');
but the output from the build task is always the same:
File Size Gzipped
dist/app.js 2024.66 KiB 452.42 KiB
The vue version is 2.6.1 and vue-router, 3.0.7.
The project has Typescript set up and I don't know f there is any relation, because in others similars projects with plain js, the lazy load in routes works fine.
Anyone has any ideia of what could be wrong in the implementation/configuration?
You can try a different config, something like this:
module.exports =
{
configureWebpack: (config) =>
{
config.optimization = {
// runtimeChunk: 'single',
moduleIds: 'hashed',
splitChunks:
{
automaticNameDelimiter: '_',
chunks: 'all',
maxInitialRequests: 5,
minSize: 5000,
// maxSize: 250000,
cacheGroups:
{
default:
{
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
vendor:
{
reuseExistingChunk: true,
test: /[\\/]node_modules[\\/]/,
name(module)
{
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
// npm package names are URL-safe, but some servers don't like # symbols
return `vendors_${packageName.replace('#', '')}`;
},
},
},
},
};
},
chainWebpack: config =>
{
config.resolve.symlinks(false);
if (process.env.NODE_ENV === 'development')
{
config.module.rule('eslint').use('eslint-loader').loader('eslint-loader').tap(options =>
{
delete options.cacheIdentifier;
options.cache = false; // otherwise on each restart cached errors won't be shown !!!
return options;
});
}
config.module.rule('vue').use('vue-loader').loader('vue-loader').tap(options =>
{
delete options.cacheDirectory;
return options;
});
config.module.rule('vue').uses.delete('cache-loader');
config.module.rule('js').uses.delete('cache-loader');
config.plugins.delete('prefetch'); // for async routes
config.plugins.delete('preload'); // for CSS
// condense whitespace in templates
config.module.rule('vue').use('vue-loader').tap(options =>
{
options.compilerOptions = { whitespace: 'condense' };
return options;
});
return config;
}
};
I have very little experience with configuring Webpack, and I'am a bit overwhelmed by this issue.
I've been working on a Vue2 project built on top of this boilerplate. The project has a folder called public which contains the entry point file index.html. Inside that index.html file I can normally access .env environment variables (e.g. process.env.VUE_APP_PAGE_TITLE).
I've included an HTML fragment inside the public folder, navbar.html, because I want it to be available for other applications via https://example.com/public/navbar.html. However, I cannot seem to get my environment variables working inside ./public/navbar.html even though they work just fine in ./public/index.html. I assume this is a problem with my webpack config.
I know I can edit my Webpack config by editing a file in my project root called vue.config.js. This file contains a configureWebpack object, but I have no idea how to make it enable environment variables inside ./public/navbar.html. Any help would be appreciated.
EDIT:
Here's my vue.config.js:
const HtmlWebpackPlugin = require('html-webpack-plugin');
function resolveClientEnv() {
const env = {};
Object.keys(process.env).forEach((key) => {
env[key] = process.env[key];
});
env.BASE_URL = '/';
return env;
}
module.exports = {
configureWebpack: {
plugins: [
new HtmlWebpackPlugin({
// This is the generated file from the build, which ends up in public/navbar.html
filename: 'navbar.html',
// This is the source file you edit.
template: 'public/navbar.html',
templateParameters: (compilation, assets, pluginOptions) => {
let stats;
return Object.assign({
// make stats lazy as it is expensive
get webpack() {
return stats || (stats = compilation.getStats().toJson());
},
compilation,
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: pluginOptions,
},
}, resolveClientEnv());
},
}),
],
},
};
This is what my custom HTMLWebpackPlugin adds to the configuration according to vue inspect:
{
options: {
template: 'public/navbar.html',
templateContent: false,
templateParameters: function () { /* omitted long function */ },
filename: 'navbar.html',
hash: false,
inject: true,
compile: true,
favicon: false,
minify: 'auto',
cache: true,
showErrors: true,
chunks: 'all',
excludeChunks: [],
chunksSortMode: 'auto',
meta: {},
base: false,
title: 'Webpack App',
xhtml: false
},
childCompilerHash: undefined,
childCompilationOutputName: undefined,
assetJson: undefined,
hash: undefined,
version: 4
}
Use this standard plugin to generate navbar.html. https://github.com/jantimon/html-webpack-plugin.
If you read the docs, the templateParameters option is what you pass env variables to. Those variables will be available in navbar.html.
This is the same plugin that vue-cli uses for index.html. If you run the vue inspect command, you can see what options they provide to the plugin. You'll need to read the source code for resolveClientEnv() to see how it works.
Example:
/* config.plugin('html-portal') */
new HtmlWebpackPlugin(
{
templateParameters: (compilation, assets, pluginOptions) => {
// enhance html-webpack-plugin's built in template params
let stats
return Object.assign({
// make stats lazy as it is expensive
get webpack () {
return stats || (stats = compilation.getStats().toJson())
},
compilation: compilation,
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: pluginOptions
}
}, resolveClientEnv(options, true /* raw */))
},
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
collapseBooleanAttributes: true,
removeScriptTypeAttributes: true
},
chunks: [
'chunk-vendors',
'chunk-common',
'portal'
],
template: 'C:\\Users\\Eric\\workspace\\arc-core\\portal\\client\\templates\\portal.html',
filename: 'portal.html',
title: 'Arc Portal'
}
),
That's a bit much, a minimal example would be:
new HtmlWebpackPlugin({
// This is the generated file from the build, which ends up in public/navbar.html
filename: 'navbar.html',
// This is the source file you edit.
template: 'templates/navbar.html',
templateParameters: {
MY_VAR: 'myVar'
}
}),
I've been trying to get this very Fine Uploader (fresh from NPM - 5.12.0-alpha) set up to push some data to S3 and I've been having some issues with chunking. I have enabled chunking I believe based on the example from Concurrent Chunking but I have not seen multiple chunks being uploaded in the XHR console.
const fu = require('fine-uploader/lib/s3');
const SA = require('superagent');
let x = new fu.s3.FineUploaderBasic({
request: {
endpoint: 'they-taken-mah-bucket.s3.amazonaws.com'
},
credentials: {
accessKey: 'invalid',
expiration: new Date(),
secretKey: 'invalid',
sessionToken: 'invalid'
},
objectProperties: {
bucket: 'they-taken-my-bucket',
key: 'filename'
},
autoUpload: false,
debug: true,
callbacks: {
onComplete: function(){
moveUpload({from:'active', to:'finished', hash: activeUpload.hash}).then( function() { good(hash); });
},
onError: function(id, name, reason, xhrCache){
moveUpload({from:'active', to:'error', hash: activeUpload.hash}).then( () => bad(new Error('upload error - '+reason)) );
},
onProgress: function(id, name, uploaded, total){
const elapsed = (Date.now() - t.getTime()) / 1000;
const rate = uploaded / elapsed;
updateUploadProgress({hash: activeUpload.hash, progress: (100*uploaded/total).toFixed(0), rate: rate});
},
chunking: {
enabled: true,
concurrent: {
enabled: true
}
},
maxConnections: 5,
retry: {
enableAuto: true,
maxAutoAttempts: 10
},
onCredentialsExpired: function () {
return fetchCredentials();
}
}
});`
The behavior I'm seeing: http://recordit.co/z5VnLR63eT
Essentially I see the OPTIONS request, that goes fine, and the upload starts correctly but I only see 1 outbound connection - and the content type is not what I would expect, it's multipart form instead of raw. Though perhaps I'm wrong in this expectation, I would have expected it to just be a raw bin post.
Any advice would be most appreciated.
Your options are not set correctly, and this is why concurrent chunking is not enabled.
You defined the chunking option inside of the callbacks section. Move it out of callbacks (along with maxConnections and retry).