Dynamically loaded Vue components giving me 404 even though the files are compiled correctly into the dist folder by webpack.
Really struggling to see why - but from what i can tell the main.js file is looking for the files relative to the current URL path that it's in.
Vue loader config
module.exports = () => {
return {
test: /\.vue$/,
use: {
loader: 'vue-loader',
}
};
}
webpack.congifg
module.exports = () => ({
entry: [
'./entry.js',
],
devtool: 'source-map',
resolve: {
extensions: ['.js', '.vue'],
modules: [path.resolve(__dirname, './dist'), 'node_modules']
},
module: require('./webpack/module')(),
plugins: require('./webpack/plugins')(),
});
The dist output looks like
when the the main.js file is trying to load the files in (1.js, 1.css) it's trying to get them relative to the url path for example
rather then it trying to get them from localhost/dist/1.js it's trying to pull them in relative to the the url i.e localhost/blog/news/1.js.
Related
I have a static Javascript project (no react, vue, etc.) where I am trying to transpile, bundle, and minify my js with webpack. I would like to have bundle.js on my layout page which will include a bunch of global js that runs on all pages and then a page_x.js file that will be on individual pages as needed. The bundle.js file might consist of several other files and should be transpiled to es5 and minified.
With my current setup, the files are running twice. I'm not sure how to fix this. I want the file included globally but also want to be able to call the function as needed. If I delete the import statement from page.js I get the console error, "doSomething" is undefined. If I only include page.js on page.html and not on _layout.html common.js is only logged out on page.html. I want "common" to be logged once on every page and I want doSomething() to be available only on page.js.
Here is an example of it running twice:
common.js
console.log("common");
export function doSomething() {
console.log("do something");
}
page.js
import {doSomething} from "/common.js";
$(button).click(doSomething);
The expected output on page load (before clicking anything) would be:
"common"
Instead I'm seeing
"common"
"common"
My webpack.config.js file is as follows:
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const RemoveEmptyScriptsPlugin = require("webpack-remove-empty-scripts");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const WebpackWatchedGlobEntries = require("webpack-watched-glob-entries-plugin");
const CssnanoPlugin = require("cssnano");
const TerserPlugin = require("terser-webpack-plugin");
const dirName = "wwwroot/dist";
module.exports = (env, argv) => {
return {
mode: argv.mode === "production" ? "production" : "development",
entry: WebpackWatchedGlobEntries.getEntries(
[
path.resolve(__dirname, "src/scripts/**/*.js"),
path.resolve(__dirname, "src/scss/maincss.scss")
]),
output: {
filename: "[name].js",
path: path.resolve(__dirname, dirName)
},
devtool: "source-map",
module: {
rules: [
{
test: /\.s[c|a]ss$/,
use:
[
MiniCssExtractPlugin.loader,
"css-loader?sourceMap",
{
loader: "postcss-loader?sourceMap",
options: {
postcssOptions: {
plugins: [
CssnanoPlugin
],
config: true
},
sourceMap: true
}
},
{ loader: "sass-loader", options: { sourceMap: true } },
]
},
{
test: /\.(svg|gif|png|eot|woff|ttf)$/,
use: [
"url-loader",
],
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"]
}
}
}
]
},
plugins: [
new WebpackWatchedGlobEntries(),
new CleanWebpackPlugin(),
new RemoveEmptyScriptsPlugin(),
new MiniCssExtractPlugin({
filename: "[name].css"
})
],
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: false,
})
]
}
};
};
Any help would be greatly appreciated.
Webpack is about building a dependency graph of your application files and finally producing one single bundle.
With your configuration, you are actually trying to use Webpack as a Multi-entry object configuration as explained in Webpack documents. The culprit here is WebpackWatchedGlobEntries plugin. For each file matched by a glob pattern, it would create a bundle which is not what you want ever. For exmaple, if you have following structure:
- src/scripts
- common.js
- some
- page1.js
- other
- page2.js
This plugin will produce multi-page application. So, you configuration:
entry: WebpackWatchedGlobEntries.getEntries(
[
path.resolve(__dirname, "src/scripts/**/*.js"),
path.resolve(__dirname, "src/scss/maincss.scss")
]),
will internally return an object as:
entry: {
"common": "src/scripts/common.js",
"some/page1": "src/scripts/some/page1.js",
"other/page2": "src/scripts/other/page2.js"
}
It means if you import common.js into page1.js and page2.js, then you are in producing three bundles and all those bundles will possess the common module which would be executed three times.
The solution really depends on how to you want to configure your bundle:
If you need to bundle as a multi-page application, then you must use splitChunk optimization that allows you to create page specific bundle while keeping shared code separate (common.js for example). Keep in mind that you do not really need to manually create a separate bundle for common.js. with split chunks, Webpack should do that automatically for you.
If you need a single bundle, you can literally go ahead and create a single bundle for entire application (most typical workflow with Webpack) and use the same bundle on each page. You can have a common function like run that can figure the code to call using URL or some unique page specific identifier. In modern SPA, that is done using routing module.
What I will suggest is to keep things simple. Do not use WebpackWatchedGlobEntries plugin. That will complicate things if you are not familiar with Webpack. Keep entry simple like this:
entry: {
// Note that you don't need common module here. It would be picked up as part of your page1 and page2 dependency graph
"page1": "src/scripts/some/page1.js",
"page2": "src/scripts/other/page2.js"
}
Then, enable the splitchunk optimization as:
optimization: {
splitChunks: {
chunks: 'all'
}
}
Again, there are multiple options to choose from. You can read more details here about preventing code duplication.
I have very basic webpack + mini-css-extract-plugin project (you can found it here).
Here is webpack.config.js:
const path = require("path");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
resolve: {
modules: [path.resolve(process.cwd(), 'node_modules')]
},
module: {
rules: [
// file loader allows to copy file to the build folder and form proper url
// usually images are used from css files, see css loader below
{
test: /\.png$/,
exclude: /node_modules/,
use: [
{
loader: 'file-loader',
options: {
name: "_assets/[name].[ext]"
}
}
]
},
// css files are processed to copy any dependent resources like images
// then they copied to the build folder and inserted via link tag
{
test: /\.css$/i,
sideEffects: true,
exclude: /node_modules/,
// for tests we use simplified raw-loader for css files
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
// public path has changed so url(...) inside css files use relative pathes
// like: url(../_assets/image.png) instead of absolute urls
publicPath: '../',
}
},
'css-loader'
]
}
]
},
plugins: [
// plugin helps to properly process css files which are imported from the source code
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: '_assets/[name].css',
chunkFilename: '_assets/[id].css'
})
],
entry: {
'test': "./src/test"
},
output: {
path: path.resolve(process.cwd(), `public`),
publicPath: '',
filename: '[name].js',
chunkFilename: '_chunks/chunk.[name].js'
}
};
main entry file test.js:
import './css/testCss.css';
console.log('Loaded');
When i run webpack build i got the following output structure:
/
|-test.js
|-_assets/
| |-test.css
When i include this js bundle into html i would expect that test.js bundle will load test.css file dynamically but this is not the case - js bundle works ok, but css file is not loaded at all.
It is only loaded when i modify source of the test.js like so:
import('./css/testCss.css'); // <--------- NOTE: dynamic import here
console.log('Loaded');
in this case after webpack build i got the following output:
/
|-test.js
|-_assets/
| |-0.css
|-_chunks/
| |-chunk.0.js
and when i load this js bundle in html - it loads both chink.0.js and 0.css
MAIN QUESTION: Is dynamic import the only correct way to include css into my js files via mini-css-extract-plugin?
Because in documentation they say yo use normal static import like import "./test.css"
my environement info:
node version: v14.12.0
webpack version: 4.44.1 (also tested on 5.2.0)
mini-css-extract-plugin version 1.1.2
I'm building a simple, non-React, html page for webcheck monitoring within a React App. This html page is called specRunner.html. From within specRunner.html I wish to invoke some JavaScript files, but am having difficulty referencing them from my html file.
To be specific, my specRunner.html file can only 'see' JS files if they are stored in the client/dist folder of my directory. I thought I was forming the file path in the tag incorrectly, but I've tested it now and can consistently access a JS file but only if that JS file is in the client/dist folder. Needless to say, I can't put my node_modules file in my client/dist folder.
To be specific I can serve up html files from anywhere in my directory (i.e., my node-express app is not limited to the client/dist file when retrieving files to serve), but my html files can't find js files unless the js file is in the client/dist file.
File structure:
root
--client
----dist
------bundle.js (for the React App)
------index.html (for the React App)
------specRunner.html (<-- my webcheck page I'm working on)
------example.js (<-- example file I'm trying to access from my specRunner.html)
----src
------React stuff
--node_modules (<-- the files I REALLY want to reference from specRunner.html)
--server
--etc.
Here's the Chrome console error when the file is anywhere but the dist folder:
Uncaught SyntaxError: Unexpected token < example.js:1
If I look in the source tab, I can see the content of the example.js file is the html of my server's default endpoint html page for any invalid endpoint calls.
This must be some React issue, even though this endpoint has no React components involved.
Here's my webpack.config:
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const SRC_DIR = path.join(__dirname, '/client/src');
const DIST_DIR = path.join(__dirname, '/client/dist');
module.exports = {
entry: `${SRC_DIR}\\index.js`,
output: {
path: path.resolve(__dirname, 'client/dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.jsx?/,
include: SRC_DIR,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015'],
plugins: ['syntax-dynamic-import'],
},
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
include: SRC_DIR,
},
],
},
resolve: {
extensions: ['.js', '.jsx']
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development'),
},
}),
new ExtractTextPlugin("styles.css"),
],
};
Grateful for any pointers!
I am using webpack for bundling. I am using reactjs and django. I want the static files used by Django and reactjs be separate. I could minified image but the minified images are saved to the folder where the output file is bundled. I want all the minified images to be saved inside frontend -> assets folder. How can i do it so?
The project structure looks like following
app - its a directory where static files are kept for Django. Webpack bundles the react files to app.js and is placed over here because Django template need it to render in its template as <script src='app/bundle/js/app.js'></script>.
frontend - It's a directory where all the react files reside. I want the images to be inside this directory(assets/images/). Images that will be used in reactjs.
How can i do it so?
my webpack right now is configured this way
const path = require("path");
if(!process.env.NODE_ENV) {
process.env.NODE_ENV = 'development';
}
module.exports = {
entry: [
'./src/index.js'
],
output: {
path: path.join("../app/static/build/", "js"),
filename: "app.js",
publicPath: "../app/static/build/"
},
devtoo: 'source-map',
debug: true,
module: {
loaders: [{
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015', 'stage-1']
}
},
{test: /\.(jpe?g|png|gif|svg)$/i, loader: "file-loader?name=images/[name].[ext]"},
]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
devServer: {
historyApiFallback: true,
contentBase: './'
}
};
You can specify custom output and public paths by using the outputPath and publicPath query name parameters:
loader: "file-loader?name=[name].[ext]&publicPath=assets/foo/&outputPath=app/images/"
But this feature isn't published to NPM yet. So unfortunatly you'll need to wait while it be published or clone and use this loader from github repo
I'm currently using Webpack to pack our Angular2 application and i'm facing a problem.
I've read several documentations but I can't achieve how to copy some files in my output directory using the file loader.
Here is my current file hierarchy :
config
| - webpack.common.js
app
|- static
| - css
| - ...
| - fonts
| - ...
| - img
| - someimage.png
| - anotherimage.png
|- main.ts
and the (full) webpack.common.js :
var path = require("path")
var webpack = require("webpack")
var ExtractTextPlugin = require("extract-text-webpack-plugin")
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
app: './app/main.ts',
},
output: {
filename: 'js/[name].js',
path:'./built',
chunkFilename: 'bundles/[id].chunk.js'
},
module: {
loaders: [
{
test: /\.ts$/,
loader: 'ts',
exclude:'./out/'
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
include: [
path.resolve(__dirname, '/app/static/img/'),
],
loader: 'file?name=[path][name].[ext]&context=./src',
}
]
},
resolve: {
extensions: ['', '.js', '.ts', '.gif']
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
]
}
To execute webpack I play the command :
webpack --config Config/webpack.common.js --bail
The ts file are correctly transpilled into javascript and copied into the output directory, the index.html file is also present but there is none of my image files.
I think there is something wrong in my configuration file but I can't see what. I'm banging my head on it fore many hours so any help will be much appreciated.
Thank you
Creating separate entry point for images may not be what you want, depending on how you build CSS part of the project. As alternative you can copy static files with copy-webpack-plugin or grunt / gulp task.
You should use url-loader to load images. Sample code is given below.
{
module: {
loaders: [
{ test: /\.(jpe?g|png|gif|svg)$/i, loader: 'url?limit=10000!img?progressive=true' }
]
}
}
Are you referring the gif files or corresponding css/sass files inside your entry js file.
entry: {
app: './app/main.ts',
}
Webpack will load all the files which have a reference in the entry point. If all your files are not in one entry point. Then you can add multiple entry points as shown below.
entry: {
app: './app/main.ts',
image: './app/something.ts'
}
Also, i would put webpack.config.js file directly in the root directory to have better access to the whole ecosystem. Try moving it from config folder to root folder.