Good Morning,
I'm quite new to Webpack and feel a bit lost - importing modules from the source path works just fine - but importing modules from node_modules (e.g. jQuery) gives me error messages that the module is not found. I am completely lost and don't even know what to look for or how to debug this further.
The error message i am getting is:
external "jquery":1 Uncaught ReferenceError: jquery is not defined
at Object.jquery (external "jquery":1)
at __webpack_require__ (bootstrap:723)
at fn (bootstrap:100)
at Object../js/ManagementApplication.ts (ManagementApplication.ts:5)
at __webpack_require__ (bootstrap:723)
at fn (bootstrap:100)
at Object.0 (dist.js:40457)
at __webpack_require__ (bootstrap:723)
at bootstrap:790
at bootstrap:790
jquery # external "jquery":1
__webpack_require__ # bootstrap:723
fn # bootstrap:100
./js/ManagementApplication.ts # ManagementApplication.ts:5
__webpack_require__ # bootstrap:723
fn # bootstrap:100
0 # dist.js:40457
__webpack_require__ # bootstrap:723
(anonymous) # bootstrap:790
(anonymous) # bootstrap:790
and here is my webpack config:
// shared config (dev and prod)
const {resolve} = require('path');
const {CheckerPlugin} = require('awesome-typescript-loader');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require("webpack")
module.exports = {
resolve: {
extensions: ['.ts', '.js'],
},
context: resolve(__dirname, '../src/main/'),
output: {
filename: "dist.js",
path: resolve(__dirname, '../target')
},
externals: {
bootstrap: "bootstrap",
jquery: "jquery"
},
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'],
},
{
test: /\.tsx?$/,
use: ['babel-loader', 'awesome-typescript-loader'],
},
{
test: /\.css$/,
use: ['style-loader', {loader: 'css-loader', options: {importLoaders: 1}}],
},
{
test: /\.(scss)$/,
use: [{
loader: 'style-loader', // inject CSS to page
}, {
loader: 'css-loader', // translates CSS into CommonJS modules
}, {
loader: 'postcss-loader', // Run postcss actions
options: {
plugins: function () { // postcss plugins, can be exported to postcss.config.js
return [
require('autoprefixer')
];
}
}
}, {
loader: 'sass-loader' // compiles Sass to CSS
}]
},
{
test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: 'url-loader?limit=10000',
},
{
test: /\.hbs/,
loaders: "handlebars-loader"
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loaders: [
'file-loader?hash=sha512&digest=hex&name=img/[hash].[ext]',
'image-webpack-loader?bypassOnDebug&optipng.optimizationLevel=7&gifsicle.interlaced=false',
],
},
],
},
plugins: [
new CheckerPlugin(),
new HtmlWebpackPlugin(),
new webpack.IgnorePlugin(/\/iconv-loader$/)
],
performance: {
hints: false,
},
};
and this one:
// development config
const merge = require('webpack-merge');
const webpack = require('webpack');
const commonConfig = require('./common');
module.exports = merge(commonConfig, {
mode: 'development',
entry: [
'webpack-dev-server/client?http://localhost:4000',// bundle the client for webpack-dev-server and connect to the provided endpoint
'webpack/hot/only-dev-server', // bundle the client for hot reloading, only- means to only hot reload for successful updates
'./js/ManagementApplication.ts' // the entry point of our app
],
devServer: {
hot: true,
host: "0.0.0.0",
port: "4000"
},
devtool: 'source-map',
plugins: [
new webpack.HotModuleReplacementPlugin(), // enable HMR globally
new webpack.NamedModulesPlugin(), // prints more readable module names in the browser console on HMR updates
],
});
(both of them are loaded, the latter one overriding the first one).
I've checked a billion times that the libraries are correctly inside node_modules - just don't know why they are not loaded. This problem is not specific only to a specific library but genreally to all libraries.
Importing css resources from libraries works fine in contrast.
Does anyone have an idea how to fix this or can help me understanding what is happening?
If you intended jquery to be treated as an external, #Pandelis answer's right (note the uppercase Q: jquery: jQuery). But in case you want to import jquery as a node module, see below.
Use jQuery as a node module
If you want to use jQuery as a node module & have it bundled, you should install jquery from npm
npm install jquery
Then import it in your code
import $ from "jquery";
No need to add anything to webpack.config.js. But if you want to use jQuery as an external:
Use jQuery as an external
When you do something like this in webpack.config.js:
...
module.exports = {
externals: {
jquery: "jQuery" // or jquery: "$"
},
...
}
It tells webpack that in the line import jquery, jquery shouldn't be bundled; instead, look for the jQuery object in the global scope (which is window in our case). Both jQuery and $ will be valid. It also means you have to load jquery from external source:
#index.html
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<sript src="bundle.js"></script>
Then in your code, you can then do
import 'jquery' // or import $ from 'jquery'
$...
Just to illustrate, you can also do externals: { foo: 'jQuery' } and import 'foo' would still work.
Hope it helps!
Not actually 100% sure without looking at more of the project but give this a go.
Set your jquery external to:
"jquery": "jQuery"
and use jquery in your project as: import jQuery from 'jquery' or import $ from 'jquery'
Related
Is it possible to get the CSS for a Vue component, and attach it as a string to a component when building a library for use at runtime?
vue-cli-service build --mode production --target lib --name components src/index.ts
I currently achieve this for some custom js using a custom block:
vue.config.js:
...
rules: [
{
resourceQuery: /blockType=client-script/,
use: './client-script-block',
},
],
},
...
client-script-block.js:
module.exports = async function () {
return `export default function (Component) {
Component.options.__client_script = ${JSON.stringify(this.resourcePath)};
}`;
};
which then exposed the string in the Vue app that uses the library. But achieving the same thing with CSS doesn't seem to play ball.
You could take a look at this CSS Extraction modules from VueLoader, that extracts the CSS from specific file or files, and stores it in a custom file, that you could then load dynamically in runtime, like:
Install:
npm install -D mini-css-extract-plugin
// webpack.config.js
var MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
// other options...
module: {
rules: [
// ... other rules omitted
{
test: /\.css$/,
use: [
process.env.NODE_ENV !== 'production'
? 'vue-style-loader'
: MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
// ... Vue Loader plugin omitted
new MiniCssExtractPlugin({
filename: 'style.css'
})
]
}
Reference: https://vue-loader.vuejs.org/guide/extract-css.html#webpack-4:
Another approach:
// webpack.config.js
var ExtractTextPlugin = require("extract-text-webpack-plugin")
module.exports = {
// other options...
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
extractCSS: true
}
}
]
},
plugins: [
new ExtractTextPlugin("style.css")
]
}
Reference: https://vue-loader-v14.vuejs.org/en/configurations/extract-css.html
Also here you have a complete guide for extracting the CSS from a SSR (Server Side Rendered) apps: https://ssr.vuejs.org/guide/css.html#enabling-css-extraction
I am serving the app through Express, which needs to use ES modules. Node does allow that, but I had to replace __dirname with another solution:
server.mjs:
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
This resulted in error with Babel, which required me to add extra plugin (https://babeljs.io/docs/en/next/babel-plugin-syntax-import-meta.html). I replaced original CRA with custom webpack and created .babelrc:
{
"presets": ["#babel/preset-env", "#babel/preset-react"],
"plugins": ["#babel/plugin-syntax-import-meta"]
}
webpack.config.js:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: "./src/index.js", // entry point to the application = top react component,
output: {
path: path.resolve(__dirname, "build"), // path where the transformed index.js will be stored
filename: "index_bundle.js", //name of the transformed file
},
module: {
rules: [
{
test: /\.(js|mjs|jsx)$/, use: {
loader: 'babel-loader',
}
}, // what files will be loaded by what procedure
{test: /\.css$/, use: ['style-loader', 'css-loader']},
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
},
],
},
]
},
mode: "development",
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html" // will take the template file and transform it to include the rest
}),
]
};
I am still runing into an error when trying to build the app. It seems that all other files are built successfully, but server.mjs is still returning an error:
ERROR in ./src/server/server.mjs 9:66
Module parse failed: Unexpected token (9:66)
File was processed with these loaders:
* ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
| import getInitialPlayerStates from "../components/functions/initialStateFunctions.mjs";
|
> var __dirname = path.resolve(path.dirname(decodeURI(new URL(import.meta.url).pathname)));
|
| var port = process.env.PORT || 4001;
# ./src/App.js 49:0-48 119:14-27
# ./src/index.js
Other .mjs files are being build alright unless I include the line with import.meta in their code - than they fail too.
What is wrong? How can I overcome this problem?
"es-dirname" library solves the problem without using "import.meta".
https://www.npmjs.com/package/es-dirname
I have multiple layouts, which depend on some shared typescript files, thats why I want to share this files with multiple layouts which are using webpack.
I'm trying to include jquery in my ajax.ts and get this error:
ERROR in ../_shared/ajax.ts
Module not found: Error: Can't resolve 'jquery' in '{...}/layouts/_shared'
_shared/ajax.ts:
import * as $ from 'jquery';
export class AjaxListener {
constructor(){
// use jquery with $
}
}
layoutA/app.ts:
import { AjaxListener } from "../_shared/ajax";
import { App } from "../_shared/app";
let app = new App();
let ajaxListener = new AjaxListener();
My Folder Structure looks like this:
/layouts
/_shared
/ajax.ts
/app.ts
/layoutA
/app.ts
/webpack.config.js
/package.json (contains "#types/jquery": "^2.0.47" and "jquery": "^3.2.1")
/tsconfig.json
tsconfig.json:
{
"compilerOptions": {
"module": "es6",
"target": "es6",
"sourceMap": true
},
"exclude": [
"node_modules",
"typings/browser",
"typings/browser.d.ts",
"typings/main",
"typings/main.d.ts"
]
}
webpack.config.js:
const ExtractTextPlugin = require("extract-text-webpack-plugin");
var path = require("path");
var distPath = path.join(__dirname, "dist");
module.exports = [
{
entry: {
app: ['./app.sass', './app.ts']
},
resolve: {
extensions: [".tsx", ".js", ".ts", ".sass"]
},
cache: false,
output: {
path: distPath,
filename: "[name]_scripts.js"
},
module: {
rules : [
{
enforce: 'pre',
// "test" is commonly used to match the file extension
test: /\.js$/,
loader: "source-map-loader"
},
{
// "test" is commonly used to match the file extension
test: /\.tsx?$/,
exclude: [/node_modules/],
use: [ 'babel-loader', 'ts-loader' ]
},
{
test: /\.sass$/,
use: [
{
loader: "style-loader" // creates style nodes from JS strings
},{
loader: "css-loader", options: { sourceMap: true } // translates CSS into CommonJS
},{
loader: "sass-loader", options: { sourceMap: true } // compiles Sass to CSS
}
]
}
]
},
devtool: "eval"
}
]
If I try to import jquery inside layoutA/app.ts file (webpack root), it works fine. Since the ajax.ts lives outside this folder, which is the best way to import libraries like jquery, lodash etc. in these files?
The following points must be observed for the best way to load js libraries in your context:
Install every js library (e.g. jquery) with a package manager like npm
To each library it needs a TypeScript definitions file (e.g. #types/jquery, to find under npmjs.com)
Install this TypeScript definition file also with npm
Note every TypeScript definition in the tsconfig.json under "files" like
"files":[
"node_modules/#types/jquery/index.d.ts",
"node_modules/#types/requirejs/index.d.ts",
]
Do this compellingly (point 1-4) with the library requirejs. This is a js file and module loader.
Now you are ready to load the js library in the TypeScript main file like:
require(["jquery", "urijs"], function($, uri) {
// your code
});
Other notes:
In the index.html file: reference under the script tags only the js bundle files, builded by e.g. webpack.
Webpack needs a TypeScript loader.
Reference exported TypeScript classes in the tsconfig.json file under 'files' and also in the TypeScript file like:
import {Car} from "./classes/Car";
Hope it helps you, to get a proper structur!
Supplement:
Try the following: reference a js library in your ayax.ts like:
private example = require("./[path to npm library]/node_modules/test/src/test.js");
If you call the library name like 'test' in the require command, then its not possible to resolve 'test'. It try to resolve over the package.json and can not find it because its outside of the root.
Am new to using webpack and used Fountain Web App to scaffold my setup and then adding in my own stuff. Am running into issues I am not sure what else to do with. I have searched and tried, but not sure if the issues are being caused by loaders or what.
When I run gulp serve or build, I get this:
C:\vapor\source\mgmtPortal\dashboard>gulp serve
[14:23:43] Loading C:\vapor\source\mgmtPortal\dashboard\gulp_tasks\browsersync.js
[14:23:43] Loading C:\vapor\source\mgmtPortal\dashboard\gulp_tasks\karma.js
[14:23:44] Loading C:\vapor\source\mgmtPortal\dashboard\gulp_tasks\misc.js
[14:23:44] Loading C:\vapor\source\mgmtPortal\dashboard\gulp_tasks\webpack.js
fallbackLoader option has been deprecated - replace with "fallback"
loader option has been deprecated - replace with "use"
[14:23:45] Using gulpfile C:\vapor\source\mgmtPortal\dashboard\gulpfile.js
[14:23:45] Starting 'serve'...
[14:23:45] Starting 'webpack:watch'...
[14:23:45] 'webpack:watch' errored after 121 ms
[14:23:45] WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
- configuration has an unknown property 'debug'. These properties are valid:
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry, externals?, loader?, module?, name?, node?, output?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
The 'debug' property was removed in webpack 2.
Loaders should be updated to allow passing this option via loader options in module.rules.
Until loaders are updated one can use the LoaderOptionsPlugin to switch loaders into debug mode:
plugins: [
new webpack.LoaderOptionsPlugin({
debug: true
})
]
at webpack (C:\vapor\source\mgmtPortal\dashboard\node_modules\webpack\lib\webpack.js:19:9)
at webpackWrapper (C:\vapor\source\mgmtPortal\dashboard\gulp_tasks\webpack.js:24:26)
at gulp.task.done (C:\vapor\source\mgmtPortal\dashboard\gulp_tasks\webpack.js:15:3)
at taskWrapper (C:\vapor\source\mgmtPortal\dashboard\node_modules\undertaker\lib\set-task.js:13:15)
at taskWrapper (C:\vapor\source\mgmtPortal\dashboard\node_modules\undertaker\lib\set-task.js:13:15)
at taskWrapper (C:\vapor\source\mgmtPortal\dashboard\node_modules\undertaker\lib\set-task.js:13:15)
at bound (domain.js:280:14)
at runBound (domain.js:293:12)
at asyncRunner (C:\vapor\source\mgmtPortal\dashboard\node_modules\async-done\index.js:36:18)
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickCallback (internal/process/next_tick.js:104:9)
at Module.runMain (module.js:606:11)
at run (bootstrap_node.js:390:7)
at startup (bootstrap_node.js:150:9)
at bootstrap_node.js:505:3
[14:23:45] 'serve' errored after 127 ms
My webpack config looks like this:
const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const autoprefixer = require('autoprefixer');
// const rules = {
// // ...
// componentStyles: {
// test: /\.scss$/,
// loaders: ["style-loader", "css-loader", "sass-loader"],
// exclude: path.resolve(__dirname, 'src/app')
// },
// fonts: {
// test: /\.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
// loader: 'file-loader?name=fonts/[name].[ext]'
// },
// // ...
// }
// const config = module.exports = {};
// config.module = {
// rules: [
// // ...
// rules.componentStyles,
// rules.fonts,
// // ...
// ]
// };
module.exports = {
module: {
// preLoaders: [{
// test: /\.js$/,
// exclude: /node_modules/,
// loader: 'eslint'
// }],
loaders: [{
test: /.json$/,
loaders: [
'json'
]
},
{
test: /\.(css|scss)$/,
loaders: [
'style',
'css',
'sass',
'postcss'
]
},
{
test: /.html$/,
loaders: [
'html'
]
}
]
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
"Tether": "tether"
}),
new HtmlWebpackPlugin({
template: conf.path.src('index.html')
}),
new webpack.ProvidePlugin({ // inject ES5 modules as global vars
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
Tether: 'tether'
}),
new webpack.ContextReplacementPlugin(
/angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
conf.paths.src
)
],
postcss: () => [autoprefixer],
debug: true,
devtool: 'source-map',
output: {
path: path.join(process.cwd(), conf.paths.tmp),
filename: 'index.js'
},
entry: `./${conf.path.src('index')}`
};
Can any of you lend a hand with helping me on this?
Thanks much.
To resolve this specific error you need to remove debug: true, from your webpack config. The error is saying that the debug parameter is not valid for Webpack 2, and it was only valid in webpack 1.
The line of the error is here:
[14:23:45] WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
- configuration has an unknown property 'debug'. These properties are valid:
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry, externals?, loader?, module?, name?, node?, output?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
The 'debug' property was removed in webpack 2.
It sounds like you upgraded to webpack 2, maybe unintentionally. If it was on purpose, you can view the migration guide here, on how to properly structure your configuration file. It likely needs more changed if you plan on staying with Webpack 2.
If it was unintentional, you can reinstall webpack by running the npm command, but it is not recommended and not supported anymore.
npm install --save webpack#1.15.0
I'm using webpack, and I want to load scss file in my JavaScript. (Or if it can be separate, it also fine).
This is my webpack config:
"use strict";
const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');
module.exports = {
context: __dirname + '/src',
entry: './js/index.js',
output: {
path: './build',
filename: 'js/app.bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
}
]
},
resolve: {
root: [
path.resolve('./src/js'),
path.resolve('./src/scss')
],
extensions: ['', '.js']
},
plugins: [
new CopyWebpackPlugin([
{ from: 'html/**', to: `${__dirname}/build/html`, flatten: true },
{ from: 'images/**', to: `${__dirname}/build/image`, flatten: true }
])
]
};
this is my files list:
src/html/index.html -> build/html/index.html (WORKED)
src/images/** -> build/images/** (WORKED)
src/js/index.js -> build/js/app.bundle.js (WORKED)
src/scss/** -> build/css/** (NOT WORKED)
This is my JavaScript code. I just started project, so not much codes:
import "babel-polyfill";
import React from 'react';
import ReactDOM from 'react-dom';
import moduleA from 'moduleA';
import "view/startup.scss";
ReactDOM.render(
<div>
<h1>Helloworld!</h1>
</div>,
document.getElementById('entry')
);
You can see this: import "view/startup.scss";
I want to load scss file into my JavaScript, but when I run webpack command, it says:
ERROR in Loader /Users/.../Desktop/work/my-project/app/node_modules/css/index.js didn't return a function
# ./scss/view/startup.scss 4:14-123
in "resolve" property of webpack config, you can see that I added another root directory for scss, also I loaded sass-loader too, but it doesn't work and I don't know why.
And as I know, with Webpack, including css/scss automatically injects into destination file, so it doesn't matter it needs to be extract as separate file, I just want that this works.
Any help will be very appreciated :)
* UPDATED *
code of ./scss/view/startup.scss
#startup {
background-color: #7087d7;
}
The error points towards the reason (I highlighted the relevant part):
ERROR in Loader /Users/.../Desktop/work/my-project/app/node_modules/css/index.js didn't return a function # ./scss/view/startup.scss 4:14-123
When you declare a loader in Webpack, you can leave off the -loader suffix (so css-loader becomes css) provided that you don't have other modules that may match the suffixless loader name.
This is where it fails in your case, because you also use the css package, which Webpack tries to use as a loader (and fails, because it's not).
To fix this, use the full loader package name:
loaders : [ "style-loader", "css-loader", "sass-loader" ]