I'm making a plain, static site (HTML/CSS/JS) with Webpack that I intend to eventually deploy to s3. I have my final HTML files exported to the root of my dist folder like, index.html, foo.html, bar.html.
When I go to localhost:9000, my index loads as expected. For foo and bar I have to type the file extension like /foo.html and /bar.html for those pages to load. Is there a setting that I'm missing that will allow me to simply type /foo and /bar in the browser and have the intended pages load?
One way I found for individual pages, is to specify a proxy using devServer.proxy. For /foo and /bar, this would look like that:
const path = require("path");
module.exports = {
...
devServer: {
static: {
directory: path.resolve(__dirname, 'dist')
},
port: 3000,
open: false,
hot: true,
proxy: {
'/foo': {
target: 'http://localhost:3000/foo.html',
pathRewrite: { '^/foo': '' }
},
'/bar': {
target: 'http://localhost:3000/bar.html',
pathRewrite: { '^/bar': '' }
}
}
}
}
Check the DevServer documentation for more options.
In addition to Nikolai's answer, in case you need your local dev server to serve urls w/o extensions in router history mode, just use the following:
historyApiFallback: {
rewrites: [
{ from: /^\/$/, to: '/views/landing.html' },
{ from: /^\/subpage/, to: '/views/subpage.html' },
{ from: /./, to: '/views/404.html' },
],
},
Source: https://webpack.js.org/configuration/dev-server/#devserverhistoryapifallback
Related
I have a multi-page app that I need some pages to show only in my development environment. This is my vue.config.js:
module.exports = {
productionSourceMap: false,
pages: {
index: "src/main.js",
admin: {
entry: "src/main-admin.js",
template: "public/index.html",
filename: "admin"
}
}
};
I need the index page to go to my production build, but the admin to be removed from it. Is there a way to add an environment-conditional configuration on vue.config.js, or to add one vue.config.js per environment?
vue.config.js is javascript, so you can do pretty much anything you want in there. In your case you could do something like:
let config = {
productionSourceMap: false,
pages: {
index: "src/main.js",
}
}
if (process.env.NODE_ENV != 'production') {
config.pages.admin = {
entry: "src/main-admin.js",
template: "public/index.html",
filename: "admin"
}
}
module.exports = config
If you need more environments than the 'builtin' production, development etc, you can create your own by creating .env files, for example a file called .env.myenv containing NODE_ENV=myenv
https://cli.vuejs.org/guide/mode-and-env.html#modes
I'm new to this webpack thing so I was looking through some Webpack 5 tutorials online and documentation but I don't know how to fix this issue
File Structure:
dist
node_modules
src
modules
js files
style
style.css
index.html
index.js
package.json
package-lock.json
webpack.config.js
Webpack Config:
const { appendFile } = require("fs");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: 'development',
entry: {
main: path.resolve(__dirname,'src/index.js'),
},
output: {
path:path.resolve(__dirname,'dist'),
filename: 'app.bundle.js',
hashFunction: 'xxhash64',
},
devtool: 'inline-source-map',
devServer: {
static: {
directory:path.resolve(__dirname,'dist'),
watch:true,
},
port: 8080,
open: true,
hot: true,
},
//loaders
module: {
rules: [
{test: /\.css$/, use:['style-loader','css-loader']}
]
},
//plugins
plugins: [new HtmlWebpackPlugin({
title: 'To Do List',
filename: 'index.html',
template: path.resolve(__dirname,"./src/index.html")
})]
}
When I run "npm run dev" my webpage opens with the HTML/CSS/JS but nothing changes (no recompiling happens) when I make a change to my code.
Also, another weird problem that occurs is that my import statements get deleted in the index.js file on save, not sure if thats related to this or just a VScode problem
You have a place to correct in your devServer.static.directory: it should be ./, not dist. Here is the set of devServer's settings, which worked out for me:
devServer: {
port: 8080,
hot: "only",
static: {
directory: path.join(__dirname, './'),
serveIndex: true,
},
},
I was struggling with HMR aswell and it is really disappointing to end up with almost nothing, except i got it working with this approach:
devServer: {
port: 8080,
hot: false,
liveReload: true,
watchFiles: ['dist/**/*'],
open: ['http://localhost:8080/html/index.html']
}
basically i switched to liveReload to achieve same result and it works now.
P.S. you don't need to use 'open' but my html is located in dist/html/index.html and i used a link to open window with that html
Django's 'static' tag generates urls using STATIC_URL, which results in something like '/static/myapp/js/bundle.js'
Mean while, webpack-dev-server is serving bundles from the url 'localhost:3000'
My question is how do I get Django 'static' template tag to generate a different url ( which points to webpack dev server) for js bundles. Of course I can hardcode it in the template, but that would not be a good solution.
Below is my project configuration
webpack.config.js
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const BundleTracker = require('webpack-bundle-tracker')
module.exports = {
mode: 'development',
context: path.dirname(path.resolve(__dirname)),
entry: {
index: './typescript_src/index.ts',
},
output: {
path: path.resolve('./myproject/assets/myapp/bundles/'),
filename: "[name]-[hash].js"
},
resolve: {
extensions: ['.ts', '.js' ]
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
plugins: [
new CleanWebpackPlugin(),
new BundleTracker({filename: './myproject/webpack-stats.json'})
],
devServer: {
port: 3000,
publicPath: '/myapp/bundles/',
// hot: true,
headers: {
"Access-Control-Allow-Origin": "http://127.0.0.1:8000", /**Django dev server */
}
}
}
settings.py
WEBPACK_LOADER = {
'DEFAULT': {
'CACHE': not DEBUG,
'BUNDLE_DIR_NAME': 'myapp/bundles/', # must end with slash
'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
'POLL_INTERVAL': 0.1,
'TIMEOUT': None,
'IGNORE': [r'.+\.hot-update.js', r'.+\.map']
}
}
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'assets'),
)
Initially I decided webpack should serve other static files as well during development
webpack.config.js
devServer: {
port: 3000,
publicPath: '/myapp/bundles/',
contentBase: path.resolve('./myproject/assets')
// hot: true,
headers: {
"Access-Control-Allow-Origin": "http://127.0.0.1:8000", /**Django dev server */
}
settings.py
# in development mode serve from wepack dev server
if DEBUG:
STATIC_URL = 'http://localhost:3000/'
else:
STATIC_URL = '/static/'
But I later realized I have to serve static files of other apps (admin, tinymce, ...), which is impossible for webpack Dev server to reach
The problem here is that the url generated by 'render_bundle' tag of django-webpack-loader (/static/myapp/bundles/bundle-name.js) will result in a Http 404 because webpack-dev-server keeps the generated bundle in memory and not on disk
Also if I set
STATIC_URL = localhost:3000
and configure webpack-dev-server to serve other static files of my app, static files of other apps won't be served
Let's analyze the issue:
We have 2 servers and we want to route requests to one or the other based on the path requested:
"/static/webpackbundles/** ==> webpack dev server
other paths ==> django dev server
This is exactly the job of a proxy server, it can be achieved with a third server (haproxy, nginx ...), but that might seem like an overkill, especially if we know that webpack dev server can be used as a proxy! (https://webpack.js.org/configuration/dev-server/#devserverproxy)
webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'main.js',
path: '/path/to/django_project/django_project/static/webpackbundles',
publicPath: '/static/webpackbundles/',
},
devServer: {
contentBase: '/path/to/django_project/django_project/static/webpackbundles',
hot: true,
proxy: {
'!/static/webpackbundles/**': {
target: 'http://localhost:8000', // points to django dev server
changeOrigin: true,
},
},
},
};
In your django template:
<script type="text/javascript" src="{% static 'webpackbundles/main.js' %}"></script>
Now access your django app/site using webpack dev server address:
ex: http://localhost:8081
With this simple config you'll have browser auto refresh and hot module replacement.
You will not need to change anything in django, also no need for django-webpack-loader
Building on #Ejez answer, i was able to configure webpack-dev-server to serve all static files (including, media files)
webpack.config.js
module.exports = {
// project root (usually package.json dir)
context: path.dirname(path.resolve(__dirname)),
output: {
path: path.resolve('./path/to/bundles/'),
filename: "[name]-[hash].js"
},
resolve: {
extensions: ['.ts', '.js' ]
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
plugins: [
new CleanWebpackPlugin(),
new BundleTracker({filename: '/path/to/webpack-stats.json'})
],
optimization: {
splitChunks: {
chunks: 'all',
name: 'lib' // bundle all their party libraries in lib.js
}
},
devServer: {
// if you do not mind webpack serving static files of other apps
// collect them (with django collectstatic) into /static_root/static/
// this way webpack-dev-server can serve from your own app's /static/
// directory and also /static_root/static/ directory (which contains
// static files of other apps
contentBase: [path.resolve('./project'), path.resolve('./project/static_root')],
// webpack bundles will be served from http://locahost:3000/static/project/bundles/
publicPath: '/static/project/bundles/',
port: 3000,
// proxy all request except (static and media files) to django dev server
proxy: [{
context: ['**', '!/static/**', '!/media/**'],
target: 'http://localhost:8000',
changeOrigin: true,
}]
}
}
Now you can access your project from webpack-dev-server url localhost:3000. Do not forget to start both dev servers (webpack and django)
Is generally not justified using STATICFILES_DIRS,
instead use STATIC_ROOT.
If You have permission to copy static files to the project folder then use STATIC_ROOT.
I am trying to create and reuse Polymer 3 components in ASP.NET MVC application. Right now I am not sure if I am approaching the issue correctly.
So first thing, I want to run everything from IIS express.
Right now I have this issue:
Uncaught TypeError: Failed to resolve module specifier "#polymer/polymer/polymer-element.js".
Relative references must start with "/", "./", or "../".
Here is my code:
Index.cshtml:
<head>
<script src="~/Scripts/PolymerApp/node_modules/#("#webcomponents")/webcomponentsjs/webco
mponents-loader.js"></script>
<script type="module" src="~/Scripts/PolymerApp/first-element.js">
</script>
</head>
<h2>Index</h2>
<div>
<first-element></first-element>
</div>
This is my first-element.js:
import {html, PolymerElement} from '#polymer/polymer/polymer-element.js';
class FirstElement extends PolymerElement {
static get template() {
return html`
<style>
:host {
display: block;
}
</style>
<h2>Hello [[prop1]]!</h2>
`;
}
static get properties() {
return {
prop1: {
type: String,
value: 'first-element',
},
};
}
}
window.customElements.define('first-element', FirstElement);
I created this through cmd: polymer init and then chose element template.
When I run this through polymer serve on polymer`s localhost it works, so i guess there is some build process going on.
Thanks in advance. I hope that i described everything.
I've attempted to do a string replacement in the polymer generated html file using webpack and a plug-in, but it doesn't seem to find the file. Maybe someone more knowledgeable in Webpack-fu can figure out the rest.
// webpack.config.js
var webpack = require('webpack');
const ReplaceInFileWebpackPlugin = require('replace-in-file-webpack-plugin');
"use strict";
module.exports = {
entry: {
main: '/'
},
output: {
filename: "./wwwroot/dist/[name].bundle.js",
publicPath: "/temp/"
},
devServer: {
contentBase: ".",
host: "localhost",
port: 9000
}, mode: "development",
plugins: [
new ReplaceInFileWebpackPlugin([{
dir: './path/to/polymer-built-app/build/default/',
test: /\.html$/,
rules: [{
search: '/#webcomponents/',
replace: '/#{\'#webcomponents\'}/'
}]
}])
]
};
**EDIT: 08/04/2018 **
I've figured this much out:
/// <binding BeforeBuild='Run - Development' />
// webpack.config.js
var webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackStringReplacePlugin = require('html-webpack-string-replace-plugin');
"use strict";
module.exports = {
entry: {
main: './'
},
output: {
publicPath: '/',
path: path.resolve(__dirname, 'wwwroot'),
filename: "./dist/[name].bundle.js"
},
devServer: {
contentBase: ".",
host: "localhost",
port: 9000
},
mode: "development",
plugins: [
new HtmlWebpackPlugin({
"template": "./path/to/index.html",
"filename": "../path/to/Views/Shared/_PolymerLayout.cshtml"
}),
new HtmlWebpackStringReplacePlugin({
'#webcomponents':
'#Html.Raw("#webcomponents")',
'%40webcomponents':
'#Html.Raw("#webcomponents")',
'%40polymer':
'#Html.Raw("#polymer")',
'/node_modules/':
'/path/to/node_modules/',
'./src/path/to/polymer-app',
'<!-- See google short url -->':
'<!-- See google short url -->\r\n<base href="/custom/base/ref">'
})
]
};
If the .js import path starts like this:
from '#polymer/...'
Polymer 3 has a command "polymer build" that automatically translates the path to a real location:
Before:
from '#polymer/polymer/polymer-element.js';
After:
from "./node_modules/#polymer/polymer/polymer-element.js";
You can type ./node_modules/ in front to skip using the polymer build command line tool.
I have the need to import some javascript files as pure text with webpack.
All the files have a specific extension say: .mytype.js.
I have created a loader for these files using:
module.loaders = [{
test: /\.mytype.js?$/,
exclude: /(node_modules|bower_components|public\/)/,
loader: "mytype-loader"
}, ....]
I have regstered an alias to resolve my own loader
resolveLoader : {
alias : {
'mytype-loader' : path.resolve(__dirname, 'myloader.js')
}
}
At the moment myloader.js looks like this:
module.exports = source => {
console.log(source)
return(source)
}
For my dev server I have the following setup:
devServer: {
watchOptions : {
// I THOUGHT THIS WOULD STOP HOTLOAD CODE BEING ADDED??!
ignored : path.resolve(__dirname, 'mytypeFiles')
},
contentBase: CONTENT_BASE,
noInfo: true,
hot: true,
inline: true,
port: PORT,
headers : { 'Access-Control-Allow-Origin' : 'http://localhost:8888'},
host: HOST
},
All of my files with extension .mytype.js are in the mytypeFiles directory. The problem is that when I run this I get the following output from the loaders console.log
'use-strict';
function run(args, resources, meta) {
// a bunch of my code
}
;
var _temp = function () {
if (typeof __REACT_HOT_LOADER__ === 'undefined') {
return;
}
__REACT_HOT_LOADER__.register(run, 'run', 'D:/manatee-latest/manatee/src/bandicoot/resource-api/bandicoot-functions/run.bandicoot.js');
}();
However use-strict; and everything after the first function definition (which is mine) has been attached. How do I stop this hot loader code from being pre & post-fixed to my source?
Thanks in advance!