I'm working on a npm package called foobar, locally, to allow me to make changes or modifications in real time without having to publish/unpublish to improve development time and sanity.
In projectTest, I have linked foobar by using the command npm link foobar. If you don't know, the npm link flag creates a symlink to your globals (you can read more about it here: https://docs.npmjs.com/cli/link)
The projectTest happens to be a Reactjs project, written in ES2015, Webpack, babel, etc; and where I do import { x } from 'package', without any issues, etc.
As mentioned, the package foobar exists in the node_modules has a link to its development directory, but for some reason, when I try to import:
import { myFn } from 'foobar'
The following error is thrown into the console:
/foobar/lib/index.js:3
export const loadImage = () => {
^^^^^^
SyntaxError: Unexpected token export
at Object.exports.runInThisContext (vm.js:78:16)
at Module._compile (module.js:543:28)
This is not expected, based in the fact that other imports inplace work perfectly; Why doesn't this happen in the other existing imports where the code is also ES2015? It's not transpiled ahead or to a static file, but in real time AFAIK, since I have webpack setup with babel loader like:
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var AssetsPlugin = require('assets-webpack-plugin')
var assetsPluginInstance = new AssetsPlugin()
module.exports = {
devtool: 'inline-source-map',
context: path.resolve(__dirname, 'src'),
entry: [
'react-hot-loader/patch',
'webpack/hot/dev-server',
'webpack-hot-middleware/client',
'babel-polyfill',
'./js/index.js'
],
output: {
path: __dirname,
publicPath: '/assets/',
filename: 'js/bundle.js?[hash]'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
'babel-loader'
]
}
...
}
I'd like to understand the reason of this happening! So, to help me trace the issue, tried an import that is not to the node_module's linked package, but instead, to the full or relative path, for example:
import { myFn } from '/bar/zoo/lar/deep/foobar'
Where I have placed an equivalent syntax/file, of a working import that is my utils or helper functions, that I use across the project without problems. The syntax is:
export const myFn = () => {
return 'myFn call!'
}
Where I import it from my app.js let's say, like:
import { myFn } from './utils' // works fine! BUT if I DO:
import { myFn } from '/path/to/packageFoobar' // I get the syntax error!
SO user #felixKling left a nice comment about webpack node_module being ignored, which I've now tested but I still get the error after removing the node_module:
(function (exports, require, module, __filename, __dirname) { export const styleObjectParser = str => {
^^^^^^
SyntaxError: Unexpected token export
at Object.exports.runInThisContext (vm.js:78:16)
at Module._compile (module.js:543:28)
From what I can see this far, is that, in the webpack dev configuration file, only the code under the context is transpiled in run time. But I might be wrong:
module.exports = {
devtool: 'inline-source-map',
context: path.resolve(__dirname, 'src'),
entry: [
'react-hot-loader/patch',
'webpack/hot/dev-server',
'webpack-hot-middleware/client',
'babel-polyfill',
'./js/index.js'
],
I'd like to confirm that changing the syntax works perfectly fine, so this is related with the context the babel-loader runs. Even though I don't understand why the syntax error happens, even when the node_module exclusion is removed.
module.exports = {
myFn: function () {
console.log('Syntax correct! myFn works!')
}
}
I am using webpack2, node v7.4.0
I think the problem is foobar project is not transpiled when linked with npm link, but projectTest shouldn't compile foobar project, it should just link it.
You have to transpile foobar with babel before you link it in other project.
You can add a build script in package.json of foobar project to transpile code into a /dist folder, and modify the main field of package.json in this way:
"main": "./dist/index.js"
Add npm run build in your development process, in order to have dist folder updated while developing foobar.
Now projectTest should link transpiled version of foobar.
Related
I'm pretty inexperienced with webpack. I'm actually using Cloudflare Wrangler, which I believe uses Webpack 4 under the hood. In any case I have an src/index.js file and a helpers/script.js file.
my index.js file works fine, builds and compiles etc etc.
When I copy the content of helpers/script.js into the top of the index.js file, again all is good and works.
When I import script.js with either of
import human from "../helpers/script"
const human = require("../helpers/script")
then I use a webpack.config.js file that looks like
module.exports = {
target: 'webworker',
context: __dirname,
entry: './src/index.js',
mode: 'production',
module: {
rules: [
{
test: /\.index\.js$/,
use: { loader: 'worker-loader' }
}
],
},
resolve: {
extensions: ['.js'],
},
};
I can't seem, no matter what I do to get it to 'like' the imported script file.
I continually get:
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
...
Error: webpack returned an error. Try configuring `entry` in your webpack config relative to the current working directory, or setting `context = __dirname` in your webpack config.
Can anyone help me understand the requirements for being able to import a file to another js. Its amazing how hard this is to do :joy:
problem
I use <script> to import index.bundle.js which bundled by webpack5 in a HTML.But I failed.
option file
//webpack.config.js
const path = require('path');
module.exports = {
entry: {
index: '/src/index.ts'
},
output: {
path: path.join(__dirname, 'dist'),
library: 'test',
libraryTarget: 'umd',
}
}
//index.ts
export function mount() {
console.log("mount")
}
//html
<script src="dist/index.js"></script>
<script>
console.log(window.mount());
</script>
error
Uncaught TypeError: window.mount is not a function
code
I have checked the official documentation.But I can't find answer.
my code is here
use
yarn
npm run build
then open the index.html,you can find the error.
Using the config you currently have (which is not putting them on the root window object), you can access your functions with window.test.mount(), because that's what you have in library in the webpack config.
If you want to put these functions on the root window object, you'd need to do that in your code:
export function mount() {
console.log("mount")
}
window.mount = mount
// etc.
You can see this by checking out dist/index.js (dropping it in the Prettier tool online can clean it up enough to be readable).
I am developping a library that needs to work in both node and a react app. I use a webpack 4 project that generates a UMD module, but I have a problem when I try to import it in a simple webpack project.
When I use import lib from 'myLib'; lib is undefined
This is what my lib look like
export const printMsg = function() {
return "This is a message from the lib";
};
With this webpack configuration
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "mylib.js",
library: "mylib",
libraryTarget: "umd",
umdNamedDefine: true,
globalObject: `(typeof self !== 'undefined' ? self : this)`
}
};
for now I'm using a boilerplate project (https://github.com/wbkd/webpack-starter) to test.
I used npm install --save mylib to add it, and my dist code is inside my node_modules folder.
My index.js file look like this :
import "../styles/index.scss";
import lib from "watson-tile-lib";
console.log(lib);
When I run the page I got undefined in my browser console.
Any idea ?
what is your main field in package.json? It should be the builded target like:
main: "dist/mylib.js"
How can I make webpack expose my module to the browser directly to the Module name instead of using Module.default?
Here is my app setup in a simplified manner to hopefully portray what I am hoping to achieve.
webpack.config.js
module.exports = {
entry: './src/app.js',
devtool: 'source-map',
output: {
path: './lib',
filename: 'app.js',
library: 'App',
libraryTarget: 'umd',
umdNamedDefine: true
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
}
};
.babelrc
{
"presets": ["es2015"],
"plugins": ["babel-plugin-add-module-exports"]
}
app.js
export default function main() {
console.log('The default function');
}
export function other() {
console.log('A random function');
}
Because I specified "App" as the "library" in the output, my library is available in the browser as App.
The weird thing is... in order to use the default function that was exported I have to do App.default. But to use the other exported function I can do this: App.other. I would expect that I could do App() to call the default exported function, and the other would be the same App.other().
Is this standard behavior in the browser or a UMD wrapped library with webpack? This does not seem to mimic the behavior of the lodash library. Is my configuration off in some way?
However, if you take a look at the lodash library (repo) in the browser, you can see that they acheived it.
Lodash is built using webpack. If you take a look inside of the package.json for lodash, you can see that the main file is lodash.js. If you take a look at that file, it appears to be UMD wrapped (UMD definition at the bottom of the file). Therefore, when I do things like:
import _ from 'lodash';
// or
import {clamp} from 'lodash';
everything works fine.
The other thing that works fine is referencing that exact file in an HTML file:
<script src="node_modules/lodash/lodash.js"></script>
Which allows me access to the lodash object.
console.log(_) // function
console.log(_.clamp) // function clamp(number, lower, upper) { ... }
How can I get the same behavior. Lodash's webpack config is much more complicated than I need, and am not sure what I need to reverse engineer.
add libraryExport: 'default' to the output configuration of webpack;
also you don't need babel-plugin-add-module-exports.
I am trying to create a simple node module that creates a set of folders in the app that consumes it. I exported a simple createLayout function that creates the folders. I pushed my changes to git and did an npm i from another folder. Lets call the modules creator and consumer for the sake of explanation. When I try to call createLayout in consumer I am running in to several issues. I am in E:\ drive.
Below is the index.js in creator:
import {sync} from 'mkdirp';
export function createLayout(config) {
sync('./folder1');
}
And index.js in consumer:
var createLayout = require('creator').createLayout;
createLayout();
// with config createLayout({path: __dirname})
This results in creating a folder in E:\ not relative to consumer. So I tried including __dirname:
sync(__dirname + '/folder1');
Once again, this also creates a folder in E:\ not relative to consumer. I searched for bit like in various modules to see how they are doing when they are reading the config file, for instance webpack uses process.cwd. So I tried that too.
sync(process.cwd() + '/folder1');
Same, results in creating a folder in E:\ not relative to consumer. Then I tried to pass the __dirname or cwd through a config object.
// get __dirname from the `consumer` in config.path
sync(config.path + '/folder1');
But it ends up in following error:
Error: EPERM: operation not permitted, mkdir 'E:\'
I tried logging all the values in both creator and consumer:
console.log(__dirname, process.cwd(), config.path)
// creator: / / E:\projects\consumer
// consumer: E:\projects\consumer E:\projects\consumer E:\projects\consumer
I am using webpack with babel to pack the creator, plain js in consumer. I do not know what am I doing wrong. I am pretty new to nodejs ways of working.
Update
I am noticing that this is occurring only when I use webpack to build the creator. A simple module.exports works normally as anyone would expect. So I am including my webpack config file:
module.exports = {
entry: [
'./index.js'
],
output: {
filename: 'creator.js',
path: __dirname + '/dist',
library: 'creator',
libraryTarget: 'umd'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel'
}
]
},
externals: {
fs: 'fs'
}
};
Correct solution is adding this line in config:
target: 'node'
this will make webpack to ignore modules like fs and mkdirp and some other.
Now no longer need to specify externals.
Incorrect solution given before:
Just add mkdirp to externals and it will resolve you problem:
externals: {
fs: 'fs',
mkdirp: 'mkdirp'
}