• Stars
    star
    114
  • Rank 308,031 (Top 7 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 7 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🍾 universal(props => import(`./${props.page}`)) + dual css/js imports
Reactlandia Chat

babel-plugin-universal-import

Version Build Status Coverage Status Green Keeper GPA Downloads License

Installation

yarn add babel-plugin-universal-import

.babelrc:

{
  "plugins": ["universal-import"]
}

What it does

Taking from the test snapshots, it does this:

import universal from 'react-universal-component'
const UniversalComponent = universal(import('./Foo.js'))

<UniversalComponent />

           

import universal from 'react-universal-component'
import universalImport from 'babel-plugin-universal-import/universalImport.js'
import path from 'path'

const UniversalComponent = universal(universalImport({
  chunkName: () => 'Foo',
  path: () => path.join(__dirname, './Foo.js'),
  resolve: () => require.resolveWeak('./Foo.js'),
  load: () => Promise.all([
    import( /* webpackChunkName: 'Foo' */ './Foo.js')
  ]).then(proms => proms[0])
}))

<UniversalComponent />

And if you're using dynamic imports:

import universal from 'react-universal-component'
const UniversalComponent = universal(props => import(`./${props.page}`))

<UniversalComponent page='Foo' />

           

import universal from 'react-universal-component'
import universalImport from 'babel-plugin-universal-import/universalImport.js'
import path from 'path'

const UniversalComponent = universal(props => universalImport({
  chunkName: props => props.page,
  path: props => path.join(__dirname, `./${props.page}`),
  resolve: props => require.resolveWeak(`./${props.page}`),
  load: props => Promise.all([
    import( /* webpackChunkName: '[request]' */ `./${props.page}`)
  ]).then(proms => proms[0])
}));

<UniversalComponent page='Foo' />

NOTE: if you aren't using react-universal-component and you just want to serve CSS chunks from extract-css-chunks-webpack-plugin, its not a problem! extract-css-chunks is completely standalone and fully HMR

It names all your chunks using magic comments (see webpack documentation on magic comments) 🔮 behind the scenes and is derived from the imported file. This works with both static and dynamic import paths, as you can see above.

Otherwise, what it's doing is providing all the different types of requires/paths/imports/etc needed by tools like react-universal-component to universally render your component.

The targeted use-case for all this is dynamic imports where you can pass a page prop to the resulting component, thereby allowing you to create one <UniversalComponent page={page} /> for a large number of your components. This is a major upgrade to the previous way of having to make a hash of a million async components in a wrapping component. You no longer have to think about Universal Components as anything different than your other components that use simple HoCs.

And maybe even cooler to some: you don't have to do universal(() => import()). I.e. you don't have to wrap it in a function any longer when using react-universal-component, similar to dynamic(import()) in Next.js...unless of course you're making use of the extremely useful props argument.

Typescript and non-Babel environments

If you can't use babel, you can either copy what this plugin does above, or you can do a shorter version where you just put the important configuration key/vals on the 2nd options argument to universal:

import universal from 'react-universal-component'

const load = props => Promise.all([
    import( /* webpackChunkName: '[request]' */ `./${props.page}`)
  ]).then(proms => proms[0])

const UniversalComponent = universal(load, {
  chunkName: props => props.page,
  resolve: props => require.resolveWeak(`./${props.page}`)
});

notice chunkName and resolve as standard options on the 2nd options argument.

Babel Server Or Webpack < 2.2.20

If your compiling the server with Babel, set the following option so import() does not exist in the final compilation result server-side:

{
  "plugins": [
    ["universal-import", {
      "babelServer": true
    }]
  ]
}

Include additional debugging info

To prevent leaking of information, file names are not included in the final output. However, for debugging purposes, you may set the includeFileName flag option to true. This will include the path to the source file from which the import() is happening to be exposed.

{
  "plugins": [
    ["universal-import", {
      "includeFileName": true
    }]
  ]
}

Advanced magic comments

This plugin supports currying of the following magic comments defiend by Webpack to the transpiled output:

  • webpackMode
  • webpackInclude
  • webpackExclude
  • webpackIgnore
  • webpackPreload
  • webpackPrefetch

In order to pass that on to the output, you must provide each magic comment in it's own comment block, e.g.

import(
  /* webpackMode: "lazy" */
  /* webpackChunkName: "Foo" */
  "./Foo"
)

Order in which you specify them will not matter, and invalid leading comments will be stripped out. The logic for naming your webpack chunks remains the same if you specify any of these advanced options. Please refer to the webpack documentation for valid values and configurations of each of these settings.

Next Steps

Checkout the rest of the packages in the "Universal" family:

Caveat

  • For chunks to be properly created--and since their names are automatically generated for you--you can't have different chunks with the same name, say index. So instead of import(`./index`), make your imports like this: import(`../ComponentFolderA`) and import(`../ComponentFolderB`). Notice you're going back one directory--this allows the chunk name to be generated uniquely even though the entry point file is index.js for both components. In addition, if in multiple places you import the same module, make sure they both start with the same base directory name. Again, using .. is your friend. Initial dots and slashes will be stripped from the resulting chunk name.

  • To the discerning eye, you may be wondering if the return of import() is still thenable?? It is! However, if you don't call .then on it, somewhere (perhaps in the components like react-universal-component that you pass it to), then it won't perform the import. Since most of us are using modules, which we need to do something with in the then callback, that's not a problem. But if you happen to be importing a module that does its own setup, such as attaches something to the window object, well then you just need to call .then() to trigger it. That's a rare case these days, which is why we decided to go with the simplicity seen here. And yes, async await works too.

Contributing

We use commitizen, so run npm run cm to make commits. A command-line form will appear, requiring you answer a few questions to automatically produce a nicely formatted commit. Releases, semantic version numbers, tags, changelogs and publishing to NPM will automatically be handled based on these commits thanks to semantic-release. Be good.

Tests

Reviewing a package's tests are a great way to get familiar with it. It's direct insight into the capabilities of the given package (if the tests are thorough). What's even better is a screenshot of the tests neatly organized and grouped (you know the whole "a picture says a thousand words" thing).

Below is a screenshot of this module's tests running in Wallaby ("An Integrated Continuous Testing Tool for JavaScript") which everyone in the React community should be using. It's fantastic and has taken my entire workflow to the next level. It re-runs your tests on every change along with comprehensive logging, bi-directional linking to your IDE, in-line code coverage indicators, and even snapshot comparisons + updates for Jest! I requestsed that feature by the way :). It's basically a substitute for live-coding that inspires you to test along your journey.

babel-plugin-universal-import screenshot

More from FaceySpacey in Reactlandia

  • redux-first-router. It's made to work perfectly with Universal. Together they comprise our "frameworkless" Redux-based approach to what Next.js does (splitting, SSR, prefetching, routing).

More Repositories

1

react-universal-component

🚀 The final answer to a React Universal Component: simultaneous SSR + Code Splitting
JavaScript
1,696
star
2

redux-first-router

🎖 seamless redux-first routing -- just dispatch actions
JavaScript
1,568
star
3

extract-css-chunks-webpack-plugin

Extract CSS from chunks into multiple stylesheets + HMR
JavaScript
691
star
4

webpack-flush-chunks

💩 server-to-client chunk discovery + transportation for Universal Rendering
JavaScript
355
star
5

universal-demo

DEMO: Webpack Flush Chunks + React Universal Component 3.0 🚀
JavaScript
230
star
6

tracker-react

No-Config reactive React Components with Meteor
JavaScript
126
star
7

redux-first-router-demo

Kick-Ass Universal RFR Demo That Answers Your SSR + Splitting Questions
JavaScript
125
star
8

redux-first-router-link

<Link /> + <NavLink /> that mirror react-router's + a few additional props
JavaScript
55
star
9

jest-storybook-facade

JavaScript
53
star
10

babel-plugin-dual-import

NOTE: now use babel-plugin-universal-import if you're using React Universal Component
JavaScript
50
star
11

require-universal-module

Universal-Rendering Module Loading Primitives
JavaScript
28
star
12

transition-group

What React CSS Transition Group is s'posed to be
JavaScript
25
star
13

respond-framework-docs-old

25
star
14

redux-first-router-boilerplate

JavaScript
23
star
15

flush-chunks-boilerplate

💩 A boilerplate showing how to achieve Universal Code-Splitting and Universal HMR with react-loadable, webpack-flush-chunks and extract-css-chunks-webpack-plugin
JavaScript
18
star
16

redux-first-router-restore-scroll

JavaScript
13
star
17

remixx

JavaScript
12
star
18

flush-chunks-boilerplate-babel-chunknames

babel boilerplate for Webpack Flush Chunks + React Universal Component + webpack's "magic comment" feature
JavaScript
10
star
19

travis-github-status

Set statuses on github from travis for jest, flow, + eslint
JavaScript
8
star
20

extract-css-chunk

JavaScript
7
star
21

jest-redux-snap

📸 reactive test helpers for redux and jest. snap everything!!!
JavaScript
7
star
22

redux-first-router-codesandbox

HOW TO USE: https://medium.com/faceyspacey/redux-first-router-lookin-sexy-on-code-sandbox-d9d9bea15053
JavaScript
6
star
23

react-native-20-screcorder-demo

JavaScript
6
star
24

redux-first-router-navigation

JavaScript
5
star
25

flush-chunks-boilerplate-webpack

universal webpack boilerplate for Webpack Flush Chunks + React Universal Component
JavaScript
5
star
26

rudy

JavaScript
5
star
27

blog-demo

JavaScript
3
star
28

redux-first-router-demo-codesandbox

JavaScript
3
star
29

redux-first-router-scroll-container

JavaScript
3
star
30

redux-first-router-navigation-boilerplate

JavaScript
3
star
31

nucleus

JavaScript
2
star
32

universal-react-vue-loader-demo

JavaScript
2
star
33

animated-transition-group

like <ReactTransitionGroup /> + callbacks, extras and child-specific customization
JavaScript
2
star
34

universal-render

2
star
35

ck

JavaScript
1
star
36

pure-redux-router

👶 Seamless Redux-First Routing
JavaScript
1
star
37

webpack-server-middleware

Hot updates Webpack bundles on the server
JavaScript
1
star
38

rudy-match-path

JavaScript
1
star
39

flush-chunks-boilerplate-babel

babel boilerplate for Webpack Flush Chunks + React Universal Component
JavaScript
1
star
40

redux-first-router-scroll-container-native

scroll restoration for React Native using Redux First Router
JavaScript
1
star
41

coastbeachwear

Web Store for Coast Beachwear Inc.
JavaScript
1
star
42

rfr-demo-mike

Created with CodeSandbox
JavaScript
1
star