I'm trying to dynamically include a .js file at webpack compile time.
I don't want to use a context to load environmental variables, because I don't these magic variables in my code.
What I'm trying to do is use the val loader to execute a module. There use an environment variable to decide what module to import. And export that module.
However, this is causing other loaders to throw errors.
Here's my dir layout
--base
--src
app.js
test.js
webpack.config.js
rawr.js
Here my webpack.config.js file
var path = require('path');
var webpack = require('webpack');
// var process = require('process');
var env = require(process.env.NODE_ENV || './devConf.js');
module.exports = {
// Specify logical root of the sourcecode
plugins: [
new webpack.DefinePlugin(env)
],
context: path.join(__dirname, '/src'),
entry: {
app: ['bootstrap.js'],
},
// Specify where to put the results
output: {
path: path.join(__dirname, '/dist'),
filename: 'build.js'
},
// Specify logical root of package imports so as to avoid relative path everywhere
resolve: {
root: path.join(__dirname, '/src'),
// What files we want to be able to import
extensions: ['', '.js', '.css', '.less'],
},
module: {
preLoaders: [
// Lint all js before compiling
/*{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader'
}*/
],
loaders: [
{
test: /\.js$/,
query: {
presets: ['es2015']
},
exclude: /node_modules/,
loader: 'babel'
},
{
test: /\.tpl\.html$/,
exclude: /node_modules/,
loader: 'ngtemplate?relativeTo=/src/!html'
},
{
test: /\.scss$/,
loaders: ["style", "css", "sass"]
},
{
test: /\.css$/,
loaders: ["style", "css"]
}
]
},
// Dev server settings
devServer: {
contentBase: path.join(__dirname, '/dist'),
noInfo: false,
hot: true
},
// ESLint config
eslint: {
configFile: path.join(__dirname, '.eslintrc')
}
};
My js files look like this
// app.js
let b = require('val!test.js');
// test.js
var process = require('process');
loadedModule = require(process.env.NODE_ENV) // NODE_ENV='./rawr.js'
export const myString = loadedModule
// rawr.js
module.exports.test = "hello world";
The exception I'm getting:
ERROR in ./src/app/app.js
Module parse failed: /home/smaug/Projects/angular-template/node_modules/babel-loader/index.js?{"presets":["es2015"]}!/home/smaug/Projects/angular-template/src/app/app.js Line 1: Unexpected identifier
You may need an appropriate loader to handle this file type.
| 'use strict';
|
| require('angular-animate');
# ./src/bootstrap.js 7:0-18
It has nothing to do with what I'm trying to do. But if I remove the require('val!...') statment, it goes away.
Any ideas?
UPDATE:
If I change the require statement to be
let b = require('val!./test.js');
I get the following error:
ERROR in ./~/val-loader!./src/app/test.js
Module build failed: Error: Final loader didn't return a Buffer or String
at DependenciesBlock.onModuleBuild (/home/smaug/Projects/angular-template/node_modules/webpack-core/lib/NormalModuleMixin.js:299:42)
at nextLoader (/home/smaug/Projects/angular-template/node_modules/webpack-core/lib/NormalModuleMixin.js:275:25)
at /home/smaug/Projects/angular-template/node_modules/webpack-core/lib/NormalModuleMixin.js:292:15
at runSyncOrAsync (/home/smaug/Projects/angular-template/node_modules/webpack-core/lib/NormalModuleMixin.js:160:12)
at nextLoader (/home/smaug/Projects/angular-template/node_modules/webpack-core/lib/NormalModuleMixin.js:290:3)
at /home/smaug/Projects/angular-template/node_modules/webpack-core/lib/NormalModuleMixin.js:292:15
at Object.context.callback (/home/smaug/Projects/angular-template/node_modules/webpack-core/lib/NormalModuleMixin.js:148:14)
at Object.module.exports (/home/
// app.js
let b = require('val!./test.js');
This is a very confusing Error Message..
Check for the following mishaps..
import statement is pointing to the exact file;
typo errors in the file name on import statement; importing the
modules which are not present.
check whether you have installed all
the loaders like
css-loader node-sass resolve-url-loader sass-loader\
style-loader url-loader
4.import statement is empty
ex:
import * from '';
5. Services and Providers returning nothing may also cause this error.
test.js is supposed to return a string that contains the code that is supposed to be given to the module that is requiring it. So, for your example, test.js should go from this
var process = require('process');
loadedModule = require(process.env.NODE_ENV) // NODE_ENV='./rawr.js'
export const myString = loadedModule
to this
var process = require('process')
loadedModule = require('raw-loader!' + process.env.NODE_ENV)
export const myString = loadedModule
Using the "raw-loader" you will get the text code from rawr.js rather than the value that rawr.js exports. "val-loader" will then give rawr.js's code to the require in app.js and it will load that text as if it was the text of the file that you were trying to load.
That was probably a terrible explanation, but just remember that when you use val-loader, you need to return a string containing code.
Related
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 am creating a library in Javascript and I am shipping it as a bundle .js file using Webpack. The following file lib.js serves as the entry for Webpack in order to expose all the API in the library:
import * as bodies from "./bodies.js";
import * as composites from "./composites.js";
import * as connections from "./connections.js";
export var bodies = {
Body: bodies.Body,
Pyramid: composites.Pyramid
};
export var connections = {
Connection: connections.Connections
};
All the files imported basically export classes that I am referencing in lib.js:
// In bodies.js
export class Body { ... };
// In composites.js
export class Pyramid { ... };
// In connections.js
export class Connection { ... };
The file for bundling using Webpack is:
const path = require('path');
module.exports = {
entry: './lib.js',
output: {
filename: 'lib-bundle.js',
path: path.resolve(__dirname, 'out')
},
module: {
rules: [
/* In order to transpile ES6 */
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: { presets: ['env'] }
}
}
],
}
};
Webpack successfully bundle everything and I get my lib file in the end.
Problems using it
Then I use it in another project:
import * as mylib from "./lib/lib-bundle.js";
// Trying to use Pyramid
var pyramid = new mylib.bodies.Pyramid();
I use again Webpack to bundle this file into a file called start.js which i import in my page:
<script type="application/javascript" src="./start.js"></script>
However when running this page, I get an error. If I run the F12 tools and break in the bundle where I try creating an instance of the pyramid, there i can clearly see that object mylib does not have anything I have exposed. It is empty, lacking all the objects I exposed before.
What am I doing wrong?
You need to specify a libraryTarget in the output section of your webpack config file.
With it the bundle will correctly export your defined values, which
can be then imported with the various module loaders.
I suggest using libraryTarget: "umd" since it will add support for the most commonly used loaders. From the webpack docs:
This exposes your library under all the module definitions, allowing it to work with CommonJS, AMD and as global variable.
The resulting webpack config file is as follows:
const path = require('path');
module.exports = {
entry: './lib.js',
output: {
filename: 'lib-bundle.js',
path: path.resolve(__dirname, 'out'),
libraryTarget: 'umd',
},
module: {
rules: [
/* In order to transpile ES6 */
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: { presets: ['env'] }
}
}
],
}
};
Context:
I work on a project where the senior programmer decided to reduce the boilerplate code in newly created typescript files. Two examples of this boilerplate code would be importing the React library or the function that fetches and processes our localized strings.
Question:
Is it possible to have imports always available in files placed in certain folders without having to write the import tags every time?
What I've tried:
I've searched and read on the subject and found those links that talk about defining variables to use in the global space:
global.d.ts, global-modifying-module.d.ts, A typescript issue that seems to get it working
However, I was still unable to get it to work. Here is what I've tried:
At the root of the folder where I want React to be always available, I created a global.d.ts file which contains:
import * as R from "react";
declare global{
const React: typeof R;
}
With this file, the resource "React" is supposed to always be available to other files in subsequent folders. My IDE (Webstorm) recognizes that the import is there and allows me to manipulate the variable React without complaining. However, when I try to run the app, I get this error:
ReferenceError: React is not defined
I don't understand what is wrong with the code! Here is an example of the file I'm trying to render:
export default class World extends React.Component<{}, any> {
public render() {
return (<div>Hello world</div>);
}
}
From this stackoverflow question, I was under the impression that the problem could be webpack related. For the sake of completeness, here is the webpack config file we're currently using:
const webpack = require('webpack');
const path = require('path');
const BUILD_DIR = path.resolve(__dirname, './../bundles');
const WEBPACK_ENTRYFILE = path.resolve(__dirname, './../srcReact/ReactWrapper.tsx');
// `CheckerPlugin` is optional. Use it if you want async error reporting.
// We need this plugin to detect a `--watch` mode. It may be removed later
// after https://github.com/webpack/webpack/issues/3460 will be resolved.
const { CheckerPlugin } = require('awesome-typescript-loader');
const config = {
entry: [WEBPACK_ENTRYFILE],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.less']
},
output: {
path: BUILD_DIR,
filename: 'bundle.js'
},
plugins: [
new CheckerPlugin()
],
devtool: 'source-map', // Source maps support ('inline-source-map' also works)
module: {
loaders: [
{
loader: 'url-loader',
exclude: [
/\.html$/,
/\.(js|jsx)$/,
/\.(ts|tsx)$/,
/\.css$/,
/\.less$/,
/\.ttf/,
/\.woff/,
/\.woff2/,
/\.json$/,
/\.svg$/
],
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
loader: 'url-loader',
test: /\.(ttf|woff|woff2)$/
},
{
loader: "style-loader!css-loader!less-loader",
test: /\.less$/
},
{
loader: "style-loader!css-loader",
test: /\.css$/
},
{
loader: "svg-loader",
test: /\.svg$/
},
{
loader: "json-loader",
test: /\.json$/
},
{
loader: "awesome-typescript-loader",
test: /\.(ts|tsx)$/
}
]
}
};
module.exports = config;
I am certain I am missing something. Can anyone help me?
Surely already open followed a tutorial like this
To do this creates a vendor file where you import these types of "global".
./src/vendors.ts;
import "react";
Add this file a to first place at entry parameter:
entry: { 'vendors': './src/vendors.ts', 'main': './src/main.ts' }
And add CommonChunkPlugins:
plugins: [ new CommonsChunkPlugin({
name: 'vendors'
}),
Like this in AngularClass with polyfills.
So i am trying to figure out how to use webpack to replace our current brunch build process. Basically we have an angular 1 app which doesnt utilise requires or imports at all and I want to have webpack just concat+transpile the files (there are both coffee and sass files and ill need to be able to watch and create source maps using the usual settings). This angular app is sitting inside another application which is using webpack extensively.
What is the simplest way to accomplish this? Is this even possible without the app using any form of javascript modules?
Here is my current config:
var webpack = require( "webpack" );
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var path = require("path");
var glob = require("glob");
const exportConfig = {
entry: {
app: glob.sync('./front-end/applications/core/app/**/*.coffee'),
vendor: ['angular']
},
output: {
filename: "app.bundle.js",
path: path.join( __dirname, "../www_root/build" ),
},
debug: true,
module: {
loaders: [
{
test: /\.coffee$/,
loader: "coffee-loader"
},
{
test: /\.sass$/,
loaders: ["style", "css", "sass"]
},
{
test: /\.(jsx|es6)/,
exclude: /(node_modules|www_root\/bower)/,
loader: "babel",
},
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.bundle.js"),
new ExtractTextPlugin("[name].css", {
allChunks: true
}),
]
}
module.exports = exportConfig
I basically just get an output file with an error for each of the files obviously:
(function webpackMissingModule() { throw new Error("Cannot find module \"./front-end/applications/core/app/components/app/module.coffee\""); }());
Thanks!
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" ]