I'd like to use Backbone with webpack in the CommonJS style, but I need to understand how to:
Tell webpack that Backbone depends on underscore
Prevent them from automatically defaulting to AMD
It seems like imports-loader might be the answer. Do I want something like this in my configuration?
module: {
loaders: [
{
test: require.resolve('_'),
loader: 'imports?_=underscore,define=>false'
},
{
test: require.resolve('backbone'),
loader: 'imports?define=>false'
}
]
},
Also, will this make it so I don't have to do var _ = require('underscore'); before I do var Backbone = require('backbone'); everywhere?
My question might be deemed a duplicate of this, but I hope to get a little more clarification than provided in the accepted answer there.
If you've installed backbone via npm, it should be required via CommonJS. When installed, NPM modules also automatically retrieve and install their dependencies in their own node_modules folder, which means you don't have to worry about providing underscore to backbone.
Related
Is there a way to configure RequireJS to always use a specific plugin, when a certain extension has been found?
I would like to avoid to manually call the plugin like require('es6!myModule')
Some sort of a-la WebPack config is what I'm looking for, but I haven't had much luck in the docs nor the web
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: {
plugins: ['react-hot-loader/babel'],
},
}
RequireJS is very limited the support it provides for what you are trying to do. It does not have any kind of pattern matching capabilities in the general sense of the word "pattern matching". In particular, there's no way to tell RequireJS to match files with a specific extension. If you must stick with RequireJS, and the set of modules that must get the plugin is a fixed set known when you are building your application, you could generate a map like this:
map: {
"*": {
foo: "plugin!foo",
bar: "plugin!bar",
// ...
}
}
The "*" is not actually a glob or any kind of sophisticated pattern matching. It is more like an encoded keyword that means "any module".
I have an application written in TypeScript that I must be able to run through RequireJS and be able to process through Webpack. I have a few modules that are essentially JSON data. The TypeScript compiler does not like to see plugin names in module imports. So to get everything to work smoothly I keep plugin names out of the TypeScript code code and I use a map like the above to have RequireJS use the json plugin for the modules that need it. I manage the map manually because it is only a few files.
SystemJS supports loading AMD modules and has much more sophisticated configuration facilities than RequireJS. What RequireJS calls a "plugin" is called a "loader" in SystemJS. You can use the meta option to associated a loader with a pattern of files:
{
baseURL: "lib/",
paths: {
// ...
},
meta: {
"something/*.js": {
loader: "some-loader",
}
}
}
I'd like to better understand the differences between how promises are implemented in webpack. Normally, blissful ignorance was enough to get by as I mostly develop apps, but I am definately a little confused in how to properly develop a plugin/tool/lib.
In creating apps the two following approaches never caused any issues; I guess mostly cause it didn't matter
webpack.config.js - using babel-polyfill as an entry point
module.exports = {
entry: {
foo: [
'core-js/fn/promise', <-- here
'./js/index.js'
]
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader'
}
]
}
}
Q: In this approach, since it's a polyfill it modifies the global Promise?
webpack config - shimming using webpacks provide plugin
module.exports = {
entry: './js/index.js',
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader'
}
]
},
plugins: [
new webpack.ProvidePlugin({
Promise: 'es6-promise' <-- here
})
]
};
Q: Does this mean that the Promise is a module only specific to the webpack bundling process? Does the transpiled ES5 code have a local copy or es6-promise? Does it patch the global Promise?
In regards to creating a jquery plugin/tool/lib which is using babel for transpilation...
webpack.config.js - using babel-plugin-transform-runtime
module.exports = {
entry: {
foo: [
'./js/start.js'
]
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader'
}
]
}
}
.babelrc
{
"presets": [ "es2015" ],
"plugins": ["transform-runtime"] <--here
}
start.js
require('babel-runtime/core-js/promise').default = require('es6-promise'); <--here
require('plugin');
Q: This aliases the es6-promise to the babel-runtime promise and is not global but only local to the tool?
Polyfill in webpack entry
entry: ['core-js/fn/promise', './index.js']
This has the same effect as if you imported it at the top of your entry point.
In this approach, since it's a polyfill it modifies the global Promise?
Yes, this polyfill changes the global Promise. Calling it a polyfill usually means that it patches the global built-ins, although this is not strictly adhered to. If they don't change existing APIs but only provide the functionality, they are sometimes called Ponyfills.
Webpack shimming with ProvidePlugin
new webpack.ProvidePlugin({
Promise: 'es6-promise'
})
The ProvidePlugin will import the configured module at the beginning of the module that uses it when the corresponding free variable is found. A free variable is an identifier that has not been declared in the current scope. Global variables are free variables in all local scopes.
Whenever a free Promise is encountered, webpack will add the following to the beginning of the module:
var Promise = require('es6-promise');
Does this mean that the Promise is a module only specific to the webpack bundling process?
That is correct, because ProvidePlugin is webpack specific and it's very unlikely that any other tool will respect any webpack settings.
Does the transpiled ES5 code have a local copy or es6-promise?
As with any other module, it is included once by webpack and all imports refer to that module.
Does it patch the global Promise?
It will only modify the global Promise if the imported module does it explicitly. The es6-promise you're using, does not patch the global by default as shown in Auto-polyfill.
Babel transform runtime
{
"plugins": ["transform-runtime"]
}
The babel-plugin-transform-runtime uses core-js to provide missing functionalities like Promise. As you will recall, I said that core-js modifies the global Promise. This is not true for this case, because babel uses the version that doesn't pollute the global namespace, which is in core-js/library as mentioned in the core-js README. For example:
const Promise = require('core-js/library/fn/promise');
Babel will import the core-js Promise and replace Promise with the imported variable. See also the example in babel-plugin-transform-runtime - core-js aliasing. This is essentially the same thing as webpack's ProvidePlugin except that babel does not bundle up the modules, so it's just adding the import.
This aliases the es6-promise to the babel-runtime promise and is not global but only local to the tool?
It is not global because it's just a module. Babel takes your JavaScript and outputs some other JavaScript where the configured features are transpiled to ES5. You will run or bundle the resulting JavaScript and it's practically the same as if you had written ES5 in the first place.
require('babel-runtime/core-js/promise').default = require('es6-promise');
With that you modify the export and therefore the modules will use es6-promise instead. But overwriting an export is not a good idea, especially since the imports of ES modules are immutable in the spec. Babel is currently not spec-compliant in that regard. For more details see Making transpiled ES modules more spec-compliant.
Which one should you use?
It depends on what you're doing. Apart from the difference of whether they change globals or not, you can choose whichever you prefer. For instance using babel's transform runtime allows you to use it with any tool that uses babel, not just webpack.
For a library
None.
Leave the polyfill to the application developer. But you might mention that it depends on a certain feature and when the user wants to use the library in an environment that doesn't support the feature, they have to polyfill it. It's also fairly reasonable to assume that Promises are widely supported and if an application targets older environments, they will very likely have polyfilled it already. Keep in mind that this doesn't mean that you shouldn't transpile new features / syntax. This is specifically for new functionality like Promise or String.prototype.trimLeft.
For a tool
That also depends on your definition of a tool. Let's assume a tool is a piece of software that is used by developers (e.g. webpack, eslint, etc.). In that case it is exactly the same as for any app, at the end of the day it's just another app but only targeting developers. Specifically speaking about command line tools, you should decide what minimum Node version you want to support and include anything that is needed for that, you can specify that in your package.json in the engines field.
For a plugin
Plugin is a very broad term and can be anything between a library and an app. For example a webpack plugin or loader should work as is, whereas a jQuery plugin will be part of a web app and you should treat it as a library (they should probably be called library instead of plugin). Generally you want to match the guidelines of whatever you're extending. Have a look at it and see what they are targeting. For example webpack currently supports Node verions >=4.3.0, so your plugin should too.
I'm currently trying to use emoji-dictionary on my project but it fails to run!
I'm receive the index.js:2 Uncaught Error: Cannot find module "./emojis" error!
Since the reactjs tag appears, I speculate you use Webpack and you didn't set up the json-loader. emojis.json is a file from the emojilib package which is a dependency of emoji-dictionary.
Install json-loader:
npm install --save-dev json-loader
And then configure it:
module.exports = {
module: {
rules: [
{
test: /\.json$/,
use: 'json-loader'
}
]
}
}
Check out json-loader on GitHub for more information.
If this is not solving the issue, you may need to explain a little bit the context. It seems to not be related to the package itself because •it's working on my machine•. 😅
I have a TypeScript project which I am bundling with Webpack. It is a demo/docs app for an open source lib I am writing, so I want to show some of the source code as part of the docs.
In my webpack config I have:
loaders: [
{ test: /\.ts$/, loader: 'ts'},
{ test: /\.css$/, loader: 'style!raw' },
{ test: /\.html/, loader: 'html' }
]
which works fine for transpiling and bundling my TypeScript files. In one of my app components I do this:
basicCodeT: string = require('./basic-example-cmp.html');
basicCodeC: string = require('!raw!./basic-example-cmp.ts');
to load the source code into a string which I then want to display in the docs.
As you can see, there is a leading ! in the second line which I discovered seems to "bypass" the default loaders from the config and loads the raw TypeScript as a string.
In my dev build this works, but when I do a "production" build with the UglifyJsPlugin and OccurrenceOrderPlugin, I get the following output:
ERROR in ./demo/src/basic-example-cmp.html
Module build failed:
# ./demo/src/demo-app.ts 24:26-61
which corresponds to the line in the source where I try to require the raw TypeScript.
So, I want to pass basic-example-cmp.ts through the TS compiler as part of the app build, but also want to require it as raw text in the app.
My question then is: Is there a proper way to tell webpack to "ignore" loaders in specific require cases?
Is my way of prepending a ! correct? Is it a hack?
Update
Turns out my problem is simply due to the way Webpack handles HTML templates - it does not like the Angular 2 template syntax, see: https://github.com/webpack/webpack/issues/992
You can add two exclamation to ignore loaders in the webpack config file
!!raw!file.ts
one exclamation will only disable preloaders!
https://webpack.js.org/concepts/loaders/#inline
As far as I know that is the only way you are going to be able to load a file in two different ways. I expect the issue is that your paths are different in your production build.
I would suggest running webpack with the --display-error-details flag to get more info on why it fails.
Is there a proper way to tell webpack to "ignore" loaders in specific require cases?
Yes. Update your test in { test: /\.ts$/, loader: 'ts'}, as desired.
I have a React application with Components written in ES6 - transpiled via Babel and Webpack.
In some places I would like to include specific CSS files with specific Components, as suggested in react webpack cookbook
However, if in any Component file I require a static CSS asset, eg:
import '../assets/css/style.css';
Then the compilation fails with an error:
SyntaxError: <PROJECT>/assets/css/style.css: Unexpected character '#' (3:0)
at Parser.pp.raise (<PROJECT>\node_modules\babel-core\lib\acorn\src\location.js:73:13)
at Parser.pp.getTokenFromCode (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:423:8)
at Parser.pp.readToken (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:106:15)
at Parser.<anonymous> (<PROJECT>\node_modules\babel-core\node_modules\acorn-jsx\inject.js:650:22)
at Parser.readToken (<PROJECT>\node_modules\babel-core\lib\acorn\plugins\flow.js:694:22)
at Parser.pp.nextToken (<PROJECT>\node_modules\babel-core\lib\acorn\src\tokenize.js:98:71)
at Object.parse (<PROJECT>\node_modules\babel-core\lib\acorn\src\index.js:105:5)
at exports.default (<PROJECT>\node_modules\babel-core\lib\babel\helpers\parse.js:47:19)
at File.parse (<PROJECT>\node_modules\babel-core\lib\babel\transformation\file\index.js:529:46)
at File.addCode (<PROJECT>\node_modules\babel-core\lib\babel\transformation\file\index.js:611:24)
It seems that if I try and require a CSS file in a Component file, then the Babel loader will interpret that as another source and try to transpile the CSS into Javascript.
Is this expected? Is there a way to achieve this - allowing transpiled files to explicitly reference static assets that are not to be transpiled?
I have specified loaders for both .js/jsx and CSS assets as follows:
module: {
loaders: [
{ test: /\.css$/, loader: "style-loader!css-loader" },
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loader: 'babel'}
]
}
View the full webpack config file
FULL DETAILS BELOW:
webpack.common.js - A base webpack config I use, so I can share properties between dev and production.
Gruntfile.js - Gruntfile used for development. As you can see it requires the webpack config above and adds some development properties to it. Could this be causing the problem?
Html.jsx - My HTML jsx component that tries to import/require the CSS. This is an isomorphic app (using Fluxbile), hence needing to have the actual HTML as a rendered component. Using the require statement seen in this file, in any part of my application, gives the error described.
It seems to be something to do with grunt. If I just compile with webpack --config webpack.common.js then I get no errors.
Short answer: It's a node runtime error. Trying to load CSS on the server in isomorphic apps is not a good idea.
You can't require css in the component that you are rendering on the server. One way to deal with it is to check if it's a browser before requiring css.
if (process.env.BROWSER) {
require("./style.css");
}
In order to make it possible you should set process.env.BROWSER to false (or delete it) on the server
server.js
delete process.env.BROWSER;
...
// other server stuff
and set it to true for the browser. You do it with webpack's DefinePlugin in the config -
webpack.config.js
plugins: [
...
new webpack.DefinePlugin({
"process.env": {
BROWSER: JSON.stringify(true)
}
})
]
You can see this in action in gpbl's Isomorphic500 app.
If you're building an isomorphic app with ES6 and want to include CSS when rendering on the server (important so basic styles can be sent down to the client in the first HTTP response) check out the #withStyles ES7 decorator used in React Starter Kit.
This little beauty helps ensure users see your content with styles when the page is first rendered. Here's an example isomorphic app I'm building leveraging this technique. Just search the codebase for #withStyles to see how it's used. It goes a little something like this:
import React, { Component, PropTypes } from 'react';
import styles from './ScheduleList.css';
import withStyles from '../../decorators/withStyles';
#withStyles(styles)
class ScheduleList extends Component {
We had a similar problem with our isomorphic app (and a lot of other problems, you can find details here). As for the problem with CSS import, at first, we were using process.env.BROWSER. Later we've switched to babel-plugin-transform-require-ignore. It works perfectly with babel6.
All you need is to have the following section in your .babelrc
"env": {
"node": {
"plugins": [
[
"babel-plugin-transform-require-ignore", { "extensions": [".less", ".css"] }
]
]
}
}
After that run your app with BABEL_ENV='node'. Like that:
BABEL_ENV='node' node app.js.
Here is an example of how a production config can look like.
You can also try this
https://github.com/halt-hammerzeit/webpack-isomorphic-tools
or this
https://github.com/halt-hammerzeit/webpack-react-redux-isomorphic-render-example
I used this babel plugin with success to solve a similar issue with less, svg and images. But it should work with any non js assets.
It rewrites all assets imports into variables, so as long as you run the compiled code just on the server and have a bundle built with webpack for the client, it should be fine.
The only drawback is that it onlyworks with named imports, so you'll have to:
import styles from './styles.css';
in order to make it work.
Make sure you are using the loaders in your webpack config:
module: {
loaders: [
{ test: /\.jsx$/, exclude: /node_modules/, loader: "babel" },
{ test: /\.css$/, loader: "style!css" }
]
}
You probably have an error in your Webpack config where you're using the babel-loader for all files, and not just .js files. You want to use a css loader for .css files.
But you shouldn't use import for loading any other module than Javascript modules, because once imports are implemented in browsers, you will only be able to import Javascript files. Use require instead in cases where you need Webpack specific functionality.
ORIGINAL POST
Webpack uses require and Babel lets you use import from ES6 which mostly do the same thing (and Babel transpiles the import to a require statement), but they are not interchangable. Webpacks require function lets you specify more than just a module name, it lets you specify loaders as well, which you cannot do with ES6 imports. So if you want to load a CSS file, you should use require instead of import.
The reason is that Babel is just a transpiler for what's coming in ES6, and ES6 will not allow you to import CSS files. So Babel won't allow you to do that either.
I've finally realised that this error is not originating at the compile stage, but rather at runtime. Because this is an ismorphic app, the components and any dependencies they have will first be parsed on the server (ie, in node). It is this that is causing the error.
Thanks for all the suggestions, I will post more if/when I figure out how to have per-component stylesheets in an isomorphic application.
I also met the same problem when I want to do the server-side render.
So I write a postcss plugin, postcss-hash-classname.
You don't require css directly.
You require your css classname js file.
Because all you require is js file, you can do the server-side render as usual.
Besides, this plugin also use your classname and file path to generate unique hash to solve css scope problem.
You can try it!
Solved With This...
https://github.com/michalkvasnicak/babel-plugin-css-modules-transform
$ npm install --save-dev babel-plugin-css-modules-transform
Include plugin in .babelrc
{
"plugins": ["css-modules-transform"]
}
And Import Css..... Like This Anywhere You Want
const styles = require('./test.css');
OR
import css from './styles.css'
Also See This... Apart From Css Files........................................................ .
https://www.npmjs.com/package/babel-plugin-transform-assets