I'm using dynamic imports in index.js:
import('./componentA');
import('./componentB');
import('./componentC');
const myIndexVar = 'My Index Var';
index.ts is the entry point in my webpack.config.js.
The result is a single bundle containing all 4 files - index and the 3 components.
My goal is to have each of the files separately in my dist folder, so that index can load the components dynamically on demand at runtime.
i.e. at runtime I'd like to load index.js, and in turn it'll request components a-c via dynamic imports when needed.
Depending on events yields the same results:
document.body.onclick = () => import('./componentA');
If I try something like this it completely ignores the component and doesn't add it in any way to the dist folder:
let componentName = './componentA';
import(componentName);
I tried following this article:
https://webpack.js.org/guides/code-splitting/
Am I misunderstanding what's supposed to happen?
If I'm not on the right track, is there any alternative that can help me reach my goal?
Related
Is there a way to assign the file contents directly to a variable/method without webpack generating an additional variable?
Currently webpack does something like this:
index.js
import scss from './styles.scss';
console.log(scss);
output.js (actual)
const styles = '...';
console.log(styles);
I want webpack to return the content of the styles.scss file directly to the console.log() method in the output without adding styles variable.
output.js (expected)
console.log('...');
I'm currently using my custom loader for reading .scss files:
css-loader.js
const sass = require('sass');
module.exports = function(source) {
const result = sass.compile(this.resourcePath);
return 'export default `\n' + result.css + '\n`';
};
I know there is a way to do this using the require() function but it generates a lot of extra code coming from webpack. Is there any other better way to do it?
So it's really a scoping issue. So there's no real requirement to not wanting webpacks default behaviour.
Webpack has a few ways how to do that. See this other answer for how to define a global variable, which is Webpacks way of doing what you want to do.
I have the map+tilemap project created in a 3rd-party app. The whole project is a set of files, the main file (XML) representing the 2D game level map and some other files (subfiles) representing graphics and tilemaps.
I am trying to create a Webpack Loader that will compile and convert the whole map/tilemap project into JSON object, that is comfortable to use in javascript. And I still can't get how to:
How can I access subfiles (taken from relative paths from the main file), what is the way to access the current directory (where the main file is placed), and the name of the main file?
How can I explain to Webpack to track changes in all subfiles, so it will run the loader again automatically to compile the whole map/tilemap project (partial re-packing).
I spent 2 days to find any working solutions, it is possible at all?
Thanks a lot!
For the first question, webpack loader is expose the file info by this, you can do like this:
module.exports = function (source) {
const loaderContext = this;
const { sourceMap, rootContext, resourcePath } = loaderContext;
const sourceRoot = path.dirname(path.relative(context, resourcePath));
...
}
For the second question, i think that maybe you can use the module.hot to track the subfiles change, like this:
if (module.hot) {
module.hot.accept('filepath', ()=>{
...
})
}
Using React 16.13.1, I have the follow class:
import React from "react";
const path = require('path');
class Portrait extends React.Component {
render() {
const vikingName = this.props.name.toLowerCase(); // Expected output of "ulf"
return (
<div>
// below img tags go here
</div>
)
}
}
export default Portrait
I'm trying to have a the src prop of the img tags be dynamic, so when the parent component calls it, it passes the name of the viking. The file directory is name-spaced.
This works:
<img src={require('../../../../res/img/ulf/picture.png') />
Error: "Module not found at '../../../../res/img/ulf/picture.png'
<img src={require(path.join('../../../../res/img', vikingName, 'picture.png'))} />
Error: "Module not found at '../../../../res/img/ulf/picture.png'
<img src={require(`../../../../res/img/${vikingName}/picture.png`)} />
When this.props is loading correctly, (this.props.name gives expected output) and all types are String and print the correct, same path, why do the bottom two do not work?
The problem isn't your code itself. The problem lays a little deeper in how Webpack bundles your code.
Webpack bundles your code and assets and creates an entirely new folder structure and/or filenames.
Webpack will turn a folder structure like this:
src
- app.jsx
- components
- - MyComponent.jsx
- assets
- - image.jpg
into:
dist
- main.js
- image.jpg
The whole point about imports/exports is that they are static. Webpack will change all your paths behind the scenes to point towards the newly created bundled path during it's bundling process. That's why your first example works smoothly. That path has been defined before runtime, so before webpack bundles your code.
However...
Dynamic imports which are updated at runtime point towards a path which doesn't exist in your bundled code. That's why it throws an error that it can't find your file. Because there simply is no such file at that location in your bundled code.
Luckily there is a workaround for this issue
How to solve this:
It's possible to access the files path relative to your bundle using require.context. This allows you to parse your relative path to the bundled path and dynamically update your images.
This answer should be able to set you on your way.
my issue is this:
whenever I'm using the following syntax inside angular ->
let myCmp = 'test1';
let cmp = require('./components/'+myCmp+'/bootstrapCmp.component.ts');
I'm getting all the components that inside the components folder within my final bundle, not just 'test1';
(I'm using the angular 2 WebPack starter pack of the AngularClass team -
https://github.com/AngularClass/angular-starter
Had anyone this issue too?
the component I'm loading / so is all other ones are basic angular 2 components.
thanks in advance, I'm struggling with it for too much ^^
hope the solution i found for myself will help other developers :
in the webpack.common.js file i've added new file to my entry object which i called : boot.js .
so the structure is like this :
entry: {
main:['./src/polyfills.browser.ts','./src/assets/boot.ts','./src/main.browser.ts']
}
the boot.ts file, contains an object with all the relavent components that i will be using (references).
while the bunlder (wepback) is running, whenever i need some component i'm going to this object i've created inside the boot.ts file, the final bundle file contains now only the components i want.
I am trying to write a webpack plugin that will go into a directory containing html files, open each, remove new lines, and generate an object to attach as a static property to my output file (which is a var).
The object would look something like:
{
htmlFile1: '<p>some html one!</p>',
htmlFile2: '<span>some html two!</span>
}
Then I would like it to be attached to my output like:
App.templates = { .... }
The creation of the object is done. I'm just struggling with webpack and figuring out how to attach it to the main object. Should I just write it to disk and require it? Or is there a way to add it to the bundle via the plugin?
I'm using Rivets.js as a template engine and I have not been able to find anything out there that does something like this already.
Also worth noting, all I'm using is webpack and npm. No Grunt/Gulp/etc
Thanks so much!
Mike
You could use webpack's require.context to import all html files in a directory as text, process the text, and export the results as a single object:
const requireTemplate = require.context('./templates', false, /\.html$/);
module.exports = requireTemplate.keys().reduce((templateMap, templatePath) => {
const templateName = templatePath.match(/\/(\w*?)\.html/)[1]; // get filename without path and extention
templateMap[templateName] = require(templatePath);
return templateMap;
}, {});