faceyspacey / babel-plugin-universal-import Goto Github PK
View Code? Open in Web Editor NEW🍾 universal(props => import(`./${props.page}`)) + dual css/js imports
License: MIT License
🍾 universal(props => import(`./${props.page}`)) + dual css/js imports
License: MIT License
When a page is located in subfolder, the page can't be found.
Can you tell how to support loading page in subfolder, both js and css?
when i set node: false
(to reduce bytes to transfer) in my webpack frontend config i get the error:
Module not found: Error: Can't resolve 'path' in '__REPLACED__/src/app/universalComponent'
this is because the code transformed by the plugin makes use of __dirname
in the path
key wich is disabled by node: false
transformed code:
Home: __WEBPACK_IMPORTED_MODULE_4_react_universal_component___default()(__WEBPACK_IMPORTED_MODULE_2_babel_plugin_universal_import_universalImport_js___default()({
...
path: () => __WEBPACK_IMPORTED_MODULE_0_path___default.a.join(__dirname, '../containers/Home'), <------ __dirname
...
})
its fixed when i set node
to:
node = {
Buffer: false,
__dirname: true, // <------ note its enabled
__filename: false,
console: false,
global: false,
process: false,
};
instead of false
i am not sure if this can be "fixed" from your site but i think it would be good to add a note in one of the readmes of the coresponding repos like react-universal-component
i could add a note - just let me kow to wich repos it should be added
hey @faceyspacey, so in my build, i'm doing a couple of dynamic imports of redux files
import(/* webpackChunkName: 'chunks/[request]' */ `./redux/es/page-types/${pageType}/index.js`)
and other places using universal-component.
the problem that i see is that babel-universal-import
seems to be wiping out my webpackChunkName
:(
if i remove the babel plugin, my chunks get named correct.
what can/should i do to fix this? thanks
Hello there,
I'm not 100% sure that my issue is related to the babel plugin or RUC.
I created the following repository (React SSR app) to demonstrate the issue when executing an import() which is not handled by RUC (ie. as an universal component), that is breaking HMR. I use this import to polyfill the client if required.
Steps to reproduce the issue
npm start
and open your browserI spend about 3 hours on this issue but I didn't look at the sources of this plugin, and it's been a long time since I read the posts from faceyspacey, explaining what it does and how chunks ids are saved and shared between server and client.
I will try to look deeper soon, but as I can easily remove this import() in dev mode, I will first continue the work I was on. But any advice/comments would be appreciated.
The current behaviour when nesting Universal Imports ( or in my case Universal Components ) is that a
split child herits his chunkName from his parent
e.g :
file1 => ImportAsync => file2 => ImportAsync => file3
results in the following chunks :
Awaiting a better solution, ( I do not have the time right now to do it myself but maybe later )
I replaced the chunkName template to permit the use of a prefix
() => MODULE
// to
() => typeof chunkNamePrefix !== 'undefined' ? `${chunkNamePrefix}${MODULE}` : MODULE
So to get it working you have to define a chunkNamePrefix variable in the scope as follows
import universal from 'react-universal-component'
const chunkNamePrefix = 'file2-'
const UniversalComponent = universal(props => import(`./${props.page}`))
<UniversalComponent page='file3' />
↓ ↓ ↓ ↓ ↓ ↓
import universal from 'react-universal-component'
import universalImport from 'babel-plugin-universal-import/universalImport.js'
import importCss from 'babel-plugin-universal-import/importCss.js'
import path from 'path'
const chunkNamePrefix = 'file2-'
const UniversalComponent = universal(props => universalImport({
chunkName: props => typeof chunkNamePrefix !== 'undefined' ? `${chunkNamePrefix}${props.page}` : props.page,
path: props => path.join(__dirname, `./${props.page}`),
resolve: props => require.resolveWeak(`./${props.page}`),
load: props => Promise.all([
import( /* webpackChunkName: '[request]' */ `./${props.page}`),
importCss(page)
]).then(proms => proms[0])
}));
<UniversalComponent page='file3' />
I agree It's not fancy and I will mind hug the one who comes with a PRable solution
#13 seems really great but I would really enjoy to keep '[request]' as the webpackChunkName so I dont need to manually define each one of my imports in the comments
Hope it will help someone
Here is the fork : https://github.com/Aetherall/babel-plugin-universal-import
The universal
options in the example (chunkName
and resolve
) don't exist in the current react-universal-component declaration file. Interestingly, the Flow types contain the properties, though.
Can this example be updated with the appropriate options that should be passed when used in a TypeScript project or can the TypeScript definitions for react-universal-component be updated to reflect the valid options?
/cc @forabi @Alex-Krautmann
Hey guys,
I am not really sure where to put this, but before I file an issue for Chromium I wanted to check with you first:
When a stylesheets gets injected async into my html then the styles get applied but are not editable in the Chrome dev tools. Whenever I change the link element that contains the stylesheet, thus enforcing Chrome to reload the resource, the styles become editable.
After a stylesheet got injected (greyed out areas in inspector are not editable)
After Chrome has reloaded the stylesheet
Is this at all something that belongs to this babel module?
I'd like to be able to customize my chunk names so I can bundle similar pages into a single chunk. This is doable without the babel plugin, but it's a little inelegant.
const LoginPage = universal(() => import(/* webpackChunkName: "app" */ 'components/pages/login'), { chunkName: 'app' })
const DashboardPage = universal(() => import(/* webpackChunkName: "app" */ 'components/pages/dashboard'), { chunkName: 'app' })
Thoughts?
I am attempting to render a component isomorphically with react-universal-component in my typescript environment
const makeUniversal = ({ chunkName, filePath }) => {
console.log({ filePath })
const loadFn = props => Promise.all([
import(
/* webpackChunkName: '[request]' */
filePath
)
]).then(proms => proms[0])
const UniversalComponent = universal(loadFn, {
chunkName: () => `universal-${chunkName}`,
resolve: () => {
return require.resolveWeak(
// if i pass hardcoded string here, it works just fine
filePath
)
}
})
return UniversalComponent
}
const Thing = makeUniversal({
chunkName: 'large-full-width',
filePath: 'apps/large/ListingCards/FullWidthEntryPoint/container',
})
// etc
render() { return <Thing /> }
When require.resolveWeak is run through webpack, it returns the wrong module (in this case it looks as though it returns a test file that is completely unrelated) do I need to change the way I am dynamically loading my components?
^[[server] ./src/apps/large/MapSearch/components/List/__tests__/container-test.jest.js
Module not found: Error: Can't resolve 'mocks' in '/Users/lfender/source/ag.js/src/apps/large/MapSearch/components/List/__tests__'
resolve 'mocks' in '/Users/lfender/source/ag.js/src/apps/large/MapSearch/components/List/__tests__'
Parsed request is a module
its interesting that it thinks im attempting to load a tests file instead of the specified filepath
I am having issues using dynamic imports with variables in the path name. Trying to load dynamically the language. If I disable the babel-plugin-universal-import plugin or I remove the variable from the import path then it works.
webpack version: 4.41.2
babel-loader version: 8.0.6
babel-plugin-universal-import version: 4.0.0
code that is causing the issue:
return import(/* webpackChunkName: "lang-admin-[request]" */ `../Locales/${locale}.ts`);
code that DOES NOT cause the issue:
return import(/* webpackChunkName: "lang-admin-[request]" */ `../Locales/en.ts`);
webpack build error:
ERROR in ./src/frontend-admin/DataProviders/LocaleProvider.ts
Module build failed (from ./node_modules/babel-loader/lib/index.js):
TypeError: /d/Development/holdmytable-frontend/src/frontend-admin/DataP
roviders/LocaleProvider.ts: Property value expected type of string but
got null
at Object.validate (/d/Development/holdmytable-frontend/node_module
s/@babel/types/lib/definitions/utils.js:164:13)
at validateField (/d/Development/holdmytable-frontend/node_modules/
@babel/types/lib/validators/validate.js:22:9)
at validate (/d/Development/holdmytable-frontend/node_modules/@babe
l/types/lib/validators/validate.js:16:3)
at builder (/d/Development/holdmytable-frontend/node_modules/@babel
/types/lib/builders/builder.js:38:27)
at Object.StringLiteral (/d/Development/holdmytable-frontend/node_m
odules/@babel/types/lib/builders/generated/index.js:346:31)
at idOption (/d/Development/holdmytable-frontend/node_modules/babel
-plugin-universal-import/index.js:134:49)
at PluginPass.Import (/d/Development/holdmytable-frontend/node_modu
les/babel-plugin-universal-import/index.js:241:13)
at newFn (/d/Development/holdmytable-frontend/node_modules/@babel/t
raverse/lib/visitors.js:179:21)
at NodePath._call (/d/Development/holdmytable-frontend/node_modules
/@babel/traverse/lib/path/context.js:55:20)
at NodePath.call (/d/Development/holdmytable-frontend/node_modules/
@babel/traverse/lib/path/context.js:42:17)
at NodePath.visit (/d/Development/holdmytable-frontend/node_modules
/@babel/traverse/lib/path/context.js:90:31)
at TraversalContext.visitQueue (/d/Development/holdmytable-frontend
/node_modules/@babel/traverse/lib/context.js:112:16)
at TraversalContext.visitSingle (/d/Development/holdmytable-fronten
d/node_modules/@babel/traverse/lib/context.js:84:19)
at TraversalContext.visit (/d/Development/holdmytable-frontend/node
_modules/@babel/traverse/lib/context.js:140:19)
at Function.traverse.node (/d/Development/holdmytable-frontend/node
_modules/@babel/traverse/lib/index.js:84:17)
at NodePath.visit (/d/Development/holdmytable-frontend/node_modules
/@babel/traverse/lib/path/context.js:97:18)
at TraversalContext.visitQueue (/d/Development/holdmytable-frontend
/node_modules/@babel/traverse/lib/context.js:112:16)
at TraversalContext.visitSingle (/d/Development/holdmytable-fronten
d/node_modules/@babel/traverse/lib/context.js:84:19)
at TraversalContext.visit (/d/Development/holdmytable-frontend/node
_modules/@babel/traverse/lib/context.js:140:19)
at Function.traverse.node (/d/Development/holdmytable-frontend/node
_modules/@babel/traverse/lib/index.js:84:17)
at NodePath.visit (/d/Development/holdmytable-frontend/node_modules
/@babel/traverse/lib/path/context.js:97:18)
at TraversalContext.visitQueue (/d/Development/holdmytable-frontend
/node_modules/@babel/traverse/lib/context.js:112:16)
at TraversalContext.visitMultiple (/d/Development/holdmytable-front
end/node_modules/@babel/traverse/lib/context.js:79:17)
at TraversalContext.visit (/d/Development/holdmytable-frontend/node
_modules/@babel/traverse/lib/context.js:138:19)
at Function.traverse.node (/d/Development/holdmytable-frontend/node
_modules/@babel/traverse/lib/index.js:84:17)
at NodePath.visit (/d/Development/holdmytable-frontend/node_modules
/@babel/traverse/lib/path/context.js:97:18)
at TraversalContext.visitQueue (/d/Development/holdmytable-frontend
/node_modules/@babel/traverse/lib/context.js:112:16)
at TraversalContext.visitSingle (/d/Development/holdmytable-fronten
d/node_modules/@babel/traverse/lib/context.js:84:19)
at TraversalContext.visit (/d/Development/holdmytable-frontend/node
_modules/@babel/traverse/lib/context.js:140:19)
at Function.traverse.node (/d/Development/holdmytable-frontend/node
_modules/@babel/traverse/lib/index.js:84:17)
at NodePath.visit (/d/Development/holdmytable-frontend/node_modules
/@babel/traverse/lib/path/context.js:97:18)
at TraversalContext.visitQueue (/d/Development/holdmytable-frontend
/node_modules/@babel/traverse/lib/context.js:112:16)
at TraversalContext.visitSingle (/d/Development/holdmytable-fronten
d/node_modules/@babel/traverse/lib/context.js:84:19)
at TraversalContext.visit (/d/Development/holdmytable-frontend/node
_modules/@babel/traverse/lib/context.js:140:19)
at Function.traverse.node (/d/Development/holdmytable-frontend/node
_modules/@babel/traverse/lib/index.js:84:17)
at NodePath.visit (/d/Development/holdmytable-frontend/node_modules
/@babel/traverse/lib/path/context.js:97:18)
webpack babel rule config:
test: /\.(tsx?)|(js)$/,
include: path.resolve(__dirname, 'src'),
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
"@babel/preset-react",
"@babel/preset-env",
],
plugins: [
"@babel/plugin-syntax-dynamic-import",
"universal-import",
]
}
}
},```
I currently use import() in my application for both view-related files (RFR-connected) and things like polyfills and message files. Currently the babel plugin transpiles all import() in the same way and adds a importCSS
to the chain which results in a warning because there is no such file.
I just thought about whether we can make this better controllable e.g. by also using some kind of command dialect e.g. like the magic comments by webpack or plain a simple using a different kind of method call e.g. instead of import()
just use importWithCSS()
.
Hey, I'm having an issue where I'm using extract-text-webpack-plugin
with codesplitting (currently react-loadable):
const LoadableFeatures = Loadable({
loader: () => import('../components/features'),
loading: Loading,
});
and this is using syntax-dynamic-import
. I'm trying to figure out what combination of things I need to do to use your libraries since they seem to be solving the thing I want.
Do I need react-universal-component
or just babel-plugin-universal-import
? How do I dynamically load a component that has its own CSS and have that CSS chunked?
I've tried just using react-universal-component
by itself:
const LoadablePricing = universal(() => import('../components/pricing'));
and the CSS doesn't get extracted to its own chunk.
What exactly doesn't work well with link.onload and how does this fix it?
// link.onload doesn't work well enough, but this will handle it
// since images can't load css (this is a popular fix)
var img = document.createElement('img')
img.onerror = function() {
link.onerror = img.onerror = null // avoid mem leaks in IE.
clearTimeout(timeout)
resolve()
}
I have cloned the latest dev
branch of react-boilerplate which uses react-loadable
and works correctly in IE11. After switching out react-loadable
for react-universal-component
and adding universal-import
I saw this error when loading the site in IE11:
Objects are not valid as a React child (found: object with keys {$$typeof, type, key, ref, props, _owner, _store}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of `App__AppWrapper`.
The source is here, I have added only the one commit. There is no SSR and no CSS to extract so the related libraries from this suite is not used.
Do you have any idea what might be wrong? Did I miss a step in setting up the universal-*
components?
On the server side while trying to resolve the dynamic import I receive error message that load is not a function
.
It's probably because transpiled object is thennable
.
My code example: Promise.resolve(import('./components/pages/SomePageITryToImport'))
.
What's the recommended solution? Right now I have to check if i am on the server to avoid resolving. Is there any way to configure makeThennable
?
We rely on a flat build folder, currently the plugin includes folder separators which causes the written chunks to be nested.
if OK, I would like to make a PR to replace or escape the /
for chunks to remain flat
I have my entire SSR/code-splitting TSX project going smoothly, and I saw I could reduce my build times somewhat by using hard-source-webpack-plugin
. This works fine the first time, and everything looks fine, but the second time, I get a warning for any given page I try to load:
[FLUSH CHUNKS]: Unable to find Pages/ReadWrite in Webpack chunks. Please check usage of Babel plugin.
and none of my CSS is rendered into the page. Is there a solution or recommendation for this, or should I try to ask the hard-source team, or should I just stop microoptimizing?
The Babel plugin currently transpiles a plain JS import into a Promise.all
with multiple imports which are all returning Promises. I have a use case which has an additional but comparable need. In our application we have route-specific message files which are used for translating messages. There is one message file for each language for each route.
Ideally it would be possible to load these things together with the JS and CSS in parallel but depending on the users locale.
Language detection and file loading can be implemented using a helper method like importCSS("chunkName")
e.g. importMessages("chunkName")
.
Only outstanding issue here might be how importMessages
receives the information about the current locale. Probably one have to inject this info into the HTML page like we do for CSS_CHUNKS
right now.
There is one difference to CSS though: Message files have to be loaded dynamically on the server too, otherwise server side rendering with differ from client side rendering.
Hey dude
Im using your babel-server so i dont need a build on both sides.
I was able to get scss to work, but ive got some scenarios where i need to provide variables and mixins to each file (global colors and stuff)
As you can imagine the compile fails because the variables are not directly imported
Is there a way to prevent a transformation from happening but still get the chunk-names for flushing?
I am getting the error: Cannot find module "path"
when using babel-plugin-universal-import
(similar to issue:
#4 )
(im using version 2.0.2
)
I have client config node: false
https://webpack.js.org/configuration/node/#node to prevent node code from ending up in the bundle (and fail fast instead of adding bloated polyfills)
Can this babel plugin be used without node code being placed into the client bundle ?
// globalHaCKS.js
window.document.stateOverride13 = 'YOLO';
renderLegacyApp();
// just_make_it_less_slow.js
import('./globalHaCKS.js'); // Doesn't work!
import('./globalHaCKS.js').then(); // Works :s
When using webpack's built in support for the import()
statement, the imported module is executed as soon as the promise is created and the chunk is downloaded. With this package, it seems that the imported module is executed only when .then()
or .catch()
is called on the promise (even though either way the chunk is downloaded as soon as the promise is created).
This seems like an unnecessary and confusing breaking change compared to the way import()
works in webpack. Any chance of changing it so that it is not necessary to call .then()
or .catch()
on the promise?
At NerdWallet we use a centralize build repo to share build settings across many apps/teams. Here is an example of the folder structure within a given app:
node_modules
-@nerdwallet/build-tool
-babelrc.js
-webpack.config.js
-node_modules
-babel-plugin-universal-import
- app.js
- webpack.config.js // inherits from @nerdwallet/build-tool
Within our build-tool's babel config we require this plugin via
require.resolve('babel-plugin-unversal-import')
. This works fine for babel plugins in general, however this plugin in particular injects an import to a hard coded path babel-plugin-unversal-import/importCss
and babel-plugin-unversal-import/universalImport
.
Because the webpack context is running from the top level, this breaks module resolution (and I have not been able to work around it with an alias).
Is it possible we can set the source via a require.resolve('./importCss')
and require.resolve('./universalImport')
such that these always resolve correctly relative to where the babel plugin is?
Happy to make a PR if this is the correct solution.
For SEO this is the error message printed:
Module not found: Error: Can't resolve 'babel-plugin-universal-import/importCss'
Module not found: Error: Can't resolve 'babel-plugin-universal-import/universalImport'
First, let me thank you for this awesome tool (alongside react-universal-component
and webpack-flush-chunks
)
I've noticed that #43 was aimed at supporting webpack magic comments which enable thinks like custom chunkNames and lazy mode. And recently, it has been introduced 2 new comments webpackPrefetch
and webpackPreload
(webpack 4.6.0) that allow you to instruct webpack to use <link rel=”prefetch/preload”>
so you can do this as a loading strategy:
universal(() => import(/* webpackChunkName: "route--home", webpackPrefetch: true */"./home"))
but unfortenately the second comment doesn't work and break the chunkName which results in route--home, webpackPrefetch: true.js
. So is there currently any plan to add support these handy features?
Thanks.
I am trying to get a component server side rendered. Two things noticed while debugging:
require.async
comes as true on server installedModules
Any idea, what it might be?
Upgraded to webpack 4.18.0 and started getting these warnings
WARNING in ./node_modules/babel-plugin-universal-import/universalImport.js 33:18-37
Critical dependency: the request of a dependency is an expression
Babel-env let you determine the plugins and polyfills you need based on your targeted browser, which is really cool
https://github.com/babel/babel/tree/master/experimental/babel-preset-env
But I'm having a hard time trying to make it work with universal-import
.
If I use a conventional .babelrc
file like this, it works perfectly:
{
"presets": ["es2015", "react", "stage-2"],
"plugins": [["emotion", { "inline": true }], "universal-import"],
"env": {
"development": {
"plugins": ["react-hot-loader/babel"]
}
}
}
But when I switch to babel-env
, universal-import
fails to transpile the imports:
This is my current .babelrc
:
{
"env": {
"devClient": {
"presets": [
["env", {
"targets": { "browsers": ["android >= 4.4", "ios_saf > 9", "and_chr >= 56"] },
"useBuiltIns": "usage"
}],
"react"
],
"plugins": [["emotion", { "inline": true }], "universal-import", "react-hot-loader/babel"],
},
"devServer": {
"presets": [
["env", {
"targets": { "node": "current" }
}],
"react"
],
"plugins": [["emotion", { "inline": true }], "universal-import"],
}
}
}
Any idea?
Hi James,
thanks for this work, it's amazing!!
I'd like to clarify one moment here. What if I have not universal components but only some js that I would like also to lazy load. I'm doing this with usual:
export default const getSomeLibrary = () => import('./some-library');
and then like
import getSomeLibrary from '../getSomeLibrary';
getSomeLibrary().then(somelibrary => somelibrary(doSomething));
(0, _universalImport3.default)({
id: './some-library',
file: '/project/app.js',
load: function load() {
return Promise.all([Promise(...), (0, _importCss3.default)('somelibrary', {})]).then(function (proms) {
return proms[0];
});
},
path: function path() {
return _path3.default.join(...);
},
resolve: function resolve() {
...
},
chunkName: function chunkName() {
return 'some-library';
}
});
and it looks like it tries to apply universal code here but it shouldn't, right?
I'm not sure whether this is the right place or whether this should be reported with babel-plugin-dynamic-import-webpack
.
It seems that these two packages conflict with each other: universal-import
transforms the import statements if it's the only plugin. When dynamic-import-webpack
gets added to the plugin list in .babelrc
then import
statements are transformed according to dynamic-import-webpack
, effectively overwriting the changes from universal-import
.
Some compiled sample code, original code looks like this:
const LandingPage = connectLandingPage(universal(() => import('./containers/landingpage')));
both plugins:
var LandingPage = (0, _reactUniversalComponent2.default)(new _promise2.default(function (resolve) {
__webpack_require__.e/* require.ensure */(2).then((function (require) {
resolve(__webpack_require__(679));
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
}));
dynamic-import-webpack
only:
var LandingPage = (0, _reactUniversalComponent2.default)(new _promise2.default(function (resolve) {
__webpack_require__.e/* require.ensure */(2).then((function (require) {
resolve(__webpack_require__(679));
}).bind(null, __webpack_require__)).catch(__webpack_require__.oe);
}));
universal-import
only:
var LandingPage = (0, _reactUniversalComponent2.default)((0, _universalImport3.default)({
id: './containers/landingpage',
file: ' [...]/ssr/app/routes.js',
load: function load() {
return _promise2.default.all([__webpack_require__.e/* import() */(2).then(__webpack_require__.bind(null, 679)), (0, _importCss3.default)('containers/landingpage')]).then(function (proms) {
return proms[0];
});
},
path: function path() {
return _path3.default.join(__dirname, './containers/landingpage');
},
resolve: function resolve() {
return /*require.resolve*/(679);
},
chunkName: function chunkName() {
return 'containers/landingpage';
}
}));
As you can see, the transform only works if universal-import
is alone. As a side effect, webpack-flush-chunks
will then not see any named chunks anymore and never bundle the correct chunks with the initial page load.
This can also be reproduced with your universal-demo
repository by just adding the dynamic-import-webpack
plugin.
Also, the plugin order in .babelrc doesn't have any effect on this behaviour.
Any ideas how to solve this?
Btw: in my project, when using universal-import
only, the code which is served to the client looks ok. But on the server, it complains about the keyword import
being in the code. Is there any case where the compiled code form this plugin looks different, depending on whether it's served for the client or for node?
Dynamic import()
should return a promiseCapability
, according to the proposal and current implementations
When using this babel plugin, that capability does not work.
Here is how I believe babel-plugin-universal-import
should work. Consider this line:
import(`./groups/core`).then(({ Paragraph }) => Paragraph);
currently, the plugin transpiles that to this:
(0, _universalImport3.default)({
id: './groups/core',
file: '/path/to/source/file.js',
load: function load() {
return Promise.all([import( /* webpackChunkName: 'groups/core' */'./groups/core'), (0, _importCss3.default)('groups/core', {})]).then(function (proms) {
return proms[0];
});
},
path: function path() {
return _path3.default.join(__dirname, './groups/core');
},
resolve: function resolve() {
return require.resolveWeak('./groups/core');
},
chunkName: function chunkName() {
return 'groups/core';
}
}).then(function (_ref) {
var Paragraph = _ref.Paragraph;
return Paragraph;
});
What it should do is attach the then(...)
statement to the promise returned by the load
method, like:
(0, _universalImport3.default)({
id: './groups/core',
file: '/path/to/source/file.js',
load: function load() {
return Promise.all([import( /* webpackChunkName: 'groups/core' */'./groups/core'), (0, _importCss3.default)('groups/core', {})]).then(function (proms) {
return proms[0];
}).then(function (_ref) {
var Paragraph = _ref.Paragraph;
return Paragraph;
});
},
path: function path() {
return _path3.default.join(__dirname, './groups/core');
},
resolve: function resolve() {
return require.resolveWeak('./groups/core');
},
chunkName: function chunkName() {
return 'groups/core';
}
});
that is because universalImport
relies on the load()
method to work: https://github.com/faceyspacey/react-universal-component/blob/master/src/requireUniversalModule.js#L124
The import()
spec shows that it returns a promise that resolves with the module, so writing import(`./groups/core`).then(({ Paragraph }) => Paragraph);
should work without any modification when using the plugin. Basically everything attached to the right-side of import(...)
, e.g. .then(...).then(...).catch(...).then(...).etc('forever and ever and on and on')
Is it expected behaviour that the build output should be flattened?
If so, shouldn't that be at least a minor, preferably a major? This was a breaking change for us.
Our output structure v1.5.1
dist/
client/
components/
component.js
containers/
container.js
Our output structure v1.5.2
dist/
client/
component.js
container.js
Thanks!
Hi everyone,
I've seen a pretty big performance improvement by using sync requires in NodeJS. I just tweaked the loadOption
function:
if (opts.isNode) {
// import('aaa') => require('aaa')
argPath.parent.callee.type = 'Identifier'
argPath.parent.callee.name = 'require'
}
else {
// import('aaa') => import(/* webpackChunkName: 'aaa-123' */ 'aaa')
argPath.addComment('leading', ` webpackChunkName: '${chunkName}' `)
otherValidMagicComments.forEach(validLeadingComment =>
argPath.addComment('leading', validLeadingComment.value)
)
}
It seems like generating multiple chunks, and then using LimitChunksWebpackPlugin to merge them all together for SSR is slow. Does my change make sense? Could it break stuff?
It seems that Uglify isn't compatible with ES6 syntax and is throwing the following error when trying to run on universalImport.js
ERROR in main.3b107cd023ec5c3b29b1.js from UglifyJs
Unexpected token: operator (>) [./node_modules/babel-plugin-universal-import/universalImport.js:7,0][main.3b107cd023ec5c3b29b1.js:24366,20]
I'm getting this when trying to run npm run build
on a fresh checkout of your other repo that uses this, https://github.com/faceyspacey/redux-first-router, causing it to fail.
I'm not using css in any of my components right now. And when I get there, I was thinking of using styled-components anyway. Is there a way to disable the no-chunk-found warning?
importCss.js:16 [UNIVERSAL-IMPORT] no chunk, chunkName , found in "window.__CSS_CHUNKS__".
I included the flushedChunks.cssHash
in my server render thinking it would suppress the first warning about the global not being found but now it just complains about specific chunks not being found.
I feel this option should be not even include the import importCss
stuff in the compiled output. I can send a PR if this is not possible yet.
Hi,
I'm trying to use this plugin in production but running webpack -p with the following config runs into issues like this one:
ERROR in main.75bf4d5ea0bac6ff91b3.js from UglifyJs
Name expected [./node_modules/babel-plugin-universal-import/index.js:3,0][main.75bf4d5ea0bac6ff91b3.js:38803,27]
The problem seems to be with es6 features but I don't know what to do about them.
Any ideas on how to fix this?
client.prod.js
const path = require('path');
const webpack = require('webpack');
const StatsPlugin = require('stats-webpack-plugin')
const AutoDllPlugin = require('autodll-webpack-plugin');
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
module.exports = {
name: 'client',
target: 'web',
devtool: 'source-map',
entry: [
'babel-polyfill',
path.resolve(__dirname, '../src/index.js'),
],
output: {
filename: '[name].[chunkhash].js',
chunkFilename: '[name].[chunkhash].js',
path: path.resolve(__dirname, '../buildClient'),
publicPath: '/static/',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.css$/,
use: ExtractCssChunks.extract({
use: {
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[local]'
}
}
})
}
]
},
resolve: {
extensions: ['.js', '.css']
},
plugins: [
//new StatsPlugin('stats.json'),
new ExtractCssChunks(),
new webpack.optimize.CommonsChunkPlugin({
names: ['bootstrap'],
filename: '[name].[chunkhash].js',
minChunks: Infinity,
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
API_URL: JSON.stringify('/'),
},
})
],
};
.babelrc
{
"presets": [
"flow",
"es2015",
"react",
"stage-2"
],
"plugins": [
"universal-import",
[
"styled-components",
{
"ssr": true
}
],
"transform-runtime",
"transform-function-bind",
"transform-decorators-legacy",
"transform-class-properties",
"transform-object-rest-spread",
[
"babel-plugin-transform-builtin-extend",
{
"globals": [
"Error",
"Array"
]
}
]
],
"env": {
"development": {
"plugins": [
"react-hot-loader/babel"
]
}
}
}
Hi,
with this source code
const MainComponent = universal(
({ pageType }) => import(
/* webpackInclude: /\.\/(product|category|home|division)-page\/index\.js$/ */
/* webpackExclude: /\/node_modules\// */
`@my-ui/${pageType}-page`
),
{
loading: Loading,
error: GeneralNoResult,
}
);
i am seeing the output of the transpiled source for webpackInlcude, webpackExclude
moved to the importCss
promise instead of the the 1st promise.
shouldnt webpackInlcude/Exclude
be part of the 1st promise (in the webpackChunkName
import)? right now webpack doesnt see the options passed in when i debug
return (0, _universalImport3.default)({
id: '@my-ui/${pageType}-page',
load: function load() {
return Promise.all([import( /* webpackChunkName: '@my-ui/[request]' */'@my-ui/' + pageType + '-page'), (0, _importCss3.default)(
/* webpackExclude: /\/node_modules\// */
'@my-ui/' + pageType + '-page', {})]).then(function (proms) {
return proms[0];
});
},
path: function path() {
return _path3.default.join(__dirname, '@my-ui/' + pageType + '-page');
},
resolve: function resolve() {
return require.resolveWeak('@my-ui/' + pageType + '-page');
},
chunkName: function chunkName() {
return '@my-ui/' + pageType + '-page';
}
});
thanks in advance
I think after accepting that pull request, babel-plugin-universal-import cannot work properly with cache-loader. Just want to say about it here.
I'm using this module along with redux-first-router and react-universal-component. Besides splitting up my presentation components i really want to split up my redux middleware, epics and reducers.
I've made pretty good progress using the onLoad in react-universal-component to include the redux ware but really what I need is a way to import my redux dependencies during the thunk for the route. Then I can async include all my extra route specific redux deps, get the state, and then try to render with the universal component.
What I've found is that using this module the result of an import
looks "wierd". When I await it returns a function rather than the whole module. I've looked at the code for both react-universal-component and universal module and i just can't wrap my head around the api that import with the plugin produces.
Is there a way to disable the babel plugin for only a few imports? I'm using webpack on both the server and the client... maybe here a short-hand way to use the result of the import ?
Trying to move to babel 7...
The build process interrupts with an error shown below (see trace).
/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/babel-plugin-universal-import/index.js:24
return baseDir.replace(/^[./]+|(\.js$)/g, '')
^
TypeError: Cannot read property 'replace' of undefined
at trimChunkNameBaseDir (/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/babel-plugin-universal-import/index.js:24:18)
at getMagicCommentChunkName (/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/babel-plugin-universal-import/index.js:64:23)
at checkForNestedChunkName (/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/babel-plugin-universal-import/index.js:164:30)
at PluginPass.Import (/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/babel-plugin-universal-import/index.js:190:33)
at newFn (/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/@babel/core/node_modules/@babel/traverse/lib/visitors.js:193:21)
at NodePath._call (/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/@babel/core/node_modules/@babel/traverse/lib/path/context.js:53:20)
at NodePath.call (/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/@babel/core/node_modules/@babel/traverse/lib/path/context.js:40:17)
at NodePath.visit (/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/@babel/core/node_modules/@babel/traverse/lib/path/context.js:88:12)
at TraversalContext.visitQueue (/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/@babel/core/node_modules/@babel/traverse/lib/context.js:118:16)
at TraversalContext.visitSingle (/home/anton/Documents/workspace-sts/nodejs-spring-cloud-app-boilerplate/node_modules/@babel/core/node_modules/@babel/traverse/lib/context.js:90:19)
error Command failed with exit code 1.
component: universal(props => import(/* webpackChunkName: 'components-Home' */ /* webpackMode: "lazy" */ '../components/Home'),
{
resolve: props => require.resolveWeak('../components/Home'),
chunkName: 'components-Home'
}),
loadData: async (store, params) => {
if(store) {
store.dispatch(actions.setMessage('Hi, I\'m from server!'))
}
return Promise.resolve()
},
When I switch the using of UC in code off and start project with only empty wrappers around the absent components, project is been built successfully.
There are two closely related issues.
First, because of the link.href
+ img.src
hack to load the chunk there are two requests made at the same time so the second one won’t utilize the browser cache.
Second, the img.src
hack downloads an uncompressed version of the resource as can be seen in this screenshot:
First we download the compressed css file via link.href
but then we download it again uncompressed via img.src
.
Now, the first issue can be resolved by moving link.href
inside the img.onerror
handler. That way we download the uncompressed version first and the second request is resolved from cache. That still leaves the second issue though.
I spotted that when I build my app in two different directories output chunks differ.
It's caused by adding full path to transpilation output:
babel-plugin-universal-import/index.js
Line 211 in 150f52c
What is this field for? Can we make it relative?
I'm trying to create a package system using universal-import
but when the dynamic part is not the last one, it fails.
This is the UniversalComponent
:
const UniversalComponent = universal(
props => import(`../../packages/${props.page}/src/pwa/index.js`)
)
The chunks create by Webpack have this structure:
This means the names of the chunks are packages/${props.page}-src-pwa-index.js
.
But webpack-flush-chunks
is trying to find packages/${props.page}/src/pwa/index.js
and the SSR fails.
[FLUSH CHUNKS]: Unable to find packages/connection/src/pwa/index.js in Webpack chunks. Please check usage of Babel plugin.
PATH /connection
DYNAMIC CHUNK NAMES RENDERED [ 'packages/connection/src/pwa/index.js' ]
SCRIPTS SERVED [ 'bootstrap.js', 'main.js' ]
STYLESHEETS SERVED [ 'main.css' ]
It works fine if the dynamic part is the last part, like in your examples:
const UniversalComponent = universal(
props => import(`../../packages/${props.page}`)
)
or if it's not dynamic:
const UniversalComponent = universal(
() => import('../../packages/general/src/pwa/index.js')
)
In the last case, the chunks created by Webpack don't contain hyphens and packages/connection/src/pwa/index.js
is the proper chunk name:
What do you think? Is it easy to fix?
Hi, I'm using this plugin in conjunction with extract-css-chunks-webpack-plugin
in order to lazy load css but since I'm not using react-universal-component
babel outputs the following warning:
WARNING in ./node_modules/babel-plugin-universal-import/universalImport.js
Module not found: Error: Can't resolve 'react-universal-component' in ...
Would it be possible to disable this warining via an option or something?
Thanks.
After that change i doesn't understand how correctly configure my project.
Now my project has next settings:
Chunk names in clientStats.namedChunkGroups
:
app/pages/showcase
On loading i have next messate in terminal:
[FLUSH CHUNKS]: Unable to find app-pages-showcase in Webpack chunks. Please check usage of Babel plugin.
Universal component i very simple on our project:
const UniversalComponent = universal(({ page }) => loaders[page]());
loaders
is simple object with loading functions:
const loaders = {
showcase: () => import('app/pages/showcase'),
welcome: () => import('app/pages/welcome'),
seoPaths: () => import('app/pages/seo-paths'),
activity: () => import('app/pages/activity'),
// .... and next few similar lines
}
Please can you describe what i must do to get work our project with last version of your great library?)
On [email protected]
everything works great)
Incrediblely hard to detect.
Server side builds seem to “remember” the first alphabetical chunk encountered. Under these conditions, the output is no longer “main” as is should be. I’ve been able to patch the issue by reverting my package-lock. Then bumping the version numbers manually inside it. I’m unsure is related directly to our plugin but there’s definitely some issue with one of the dependencies. It’s most visible by uninstalling and reinstalling. I’ve only had this issue on the universal demo and one other architecture.
Would you accept a PR to add an option to disable the CSS warnings?
Something like this:
{
"plugins": [
["universal-import", {
"disableCssWarnings": true
}]
]
}
Hey there! Just noticed that the universal-import
plugin chokes, a little cryptically, on async functions with the new Babel beta. Given this code:
const importSans = async () => {
try {
require('vendor/fonts/din')
if (!sessionStorage.getItem('sansLoaded')) {
const FontFaceObserver = await import('fontfaceobserver/fontfaceobserver.standalone')
const observer = new FontFaceObserver('PF DIN Text Pro', { weight: 400 })
await observer.load()
if (!__DEV__ && canStoreIn('sessionStorage')) sessionStorage.setItem('sansLoaded', true)
}
return true
} catch (_) {
return false
}
}
...the transpiler spits out this message:
ERROR in ./src/client.js
Module build failed: Error: /Users/daniel/Repos/Ignota/rupertsberg/src/client.js: Unexpected return value from visitor method function newFn(path) {
return fn.call(state, path, state);
}
at NodePath._call (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/path/context.js:71:13)
at NodePath.call (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/path/context.js:42:17)
at NodePath.visit (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/path/context.js:99:12)
at TraversalContext.visitQueue (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:137:18)
at TraversalContext.visitSingle (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:96:19)
at TraversalContext.visit (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:178:19)
at Function.traverse.node (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/index.js:108:17)
at NodePath.visit (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/path/context.js:110:19)
at TraversalContext.visitQueue (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:137:18)
at TraversalContext.visitSingle (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:96:19)
at TraversalContext.visit (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:178:19)
at Function.traverse.node (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/index.js:108:17)
at NodePath.visit (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/path/context.js:110:19)
at TraversalContext.visitQueue (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:137:18)
at TraversalContext.visitSingle (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:96:19)
at TraversalContext.visit (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:178:19)
at Function.traverse.node (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/index.js:108:17)
at NodePath.visit (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/path/context.js:110:19)
at TraversalContext.visitQueue (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:137:18)
at TraversalContext.visitMultiple (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:91:17)
at TraversalContext.visit (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/context.js:176:19)
at Function.traverse.node (/Users/daniel/Repos/Ignota/rupertsberg/node_modules/babel-core/node_modules/babel-traverse/lib/index.js:108:17)
@ multi ./client
Removing the async
/await
clause unbroke the build, as did downgrading to Babel v6.
Doesn't work with Babel 7:
function getUniversalImport(p) {
if (!p.hub.file[universalImportId]) {
const universal = p.hub.file.addImport(
'babel-plugin-universal-import/universalImport.js',
'default',
'universalImport'
)
p.hub.file[universalImportId] = universal
}
return p.hub.file[universalImportId]
}
Error: This API has been removed. If you're looking for this functionality in Babel 7, you should import the 'babel-helper-module-imports' module and use the functions exposed from that module, such as 'addNamed' or 'addDefault'.
I'm trying to use this babel-plugin with babel-core/register.
entry.js
require('babel-polyfill');
require('babel-core/register')({
plugins: ["universal-import"],
});
require('./server/server.js');
.babelrc
{
"presets": [
"es2015", "react", "stage-0"
],
"plugins": [
"transform-async-to-generator",
"universal-import"
]
}
client side routes
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import universal from 'react-universal-component';
const Routes = () => (
<Switch>
<Route path="/page" component={universal(import('./Page'))} />
</Switch>
);
export default Routes;
error log
$ node ./src/entry.js
/Users/erickim/Develop/front/react/test-project/src/client/index.js:39
return Promise.all([import( /* webpackChunkName: 'Page' */'./Page'), (0, _importCss3.default)('Page')]).then(function (proms) {
^^^^^^
SyntaxError: Unexpected token import
at createScript (vm.js:53:10)
at Object.runInThisContext (vm.js:95:10)
at Module._compile (module.js:543:28)
at loader (/Users/erickim/Develop/front/react/test-project/node_modules/babel-register/lib/node.js:144:5)
at Object.require.extensions.(anonymous function) [as .js] (/Users/erickim/Develop/front/react/test-project/node_modules/babel-register/lib/node.js:154:7)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.require (module.js:498:17)
at require (internal/module.js:20:19)
error Command failed with exit code 1.
No error if I'm running a webpack build, though. So I guess this might be a problem with babel-core/register
? 🤔🤔
I follow Typescript and non-Babel environments demo to configure UniversalComponent:
import universal from 'react-universal-component'
import * as path from 'path'
import universalImport from 'babel-plugin-universal-import/universalImport'
import importCss from 'babel-plugin-universal-import/importCss'
import { IStoreState } from '../../store/types'
declare const require: any
const UniversalComponent = universal((props: any) => universalImport({
chunkName: () => props.page,
path: () => path.join(__dirname, `../../page/${props.page}/${props.page}`),
resolve: () => require.resolveWeak(`../../page/${props.page}/${props.page}`),
load: () => Promise.all([
import( /* webpackChunkName: '[request]' */ `../../page/${props.page}/${props.page}`),
importCss(props.page)
]).then(proms => {
return proms[0]
})
}), {
minDelay: 500
})
When i start server, i get both warning [FLUSH CHUNKS]: Unable to find Home in Webpack chunks. Please check usage of Babel plugin
in server side and Warning: Text content did not match. Server: "Home+10" Client: "Loading..."
in client browser。
so how #to solve this problem?
or what I may have done incorrectly?
thanks in advance
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.