pepsryuu / nollup Goto Github PK
View Code? Open in Web Editor NEWRollup compatible development bundler for fast rebuilds and HMR.
License: MIT License
Rollup compatible development bundler for fast rebuilds and HMR.
License: MIT License
the PR #24 fixed the support of version 4.2.3 but not of version 5
SSE uses normal HTTP and so:
it would be easier to integrate the Nollup middleware into a custom dev server / express app
it would be easier to proxy to Nollup's dev server (because proxying WS is complicated)
as a bonus I'm found of, browsers have an auto retry on SEE, so you can have a cheap "browser automatically picks server back up, after a server restart"
Maybe I've done something wrong but even with the dumbest config ever I feel like I have an error while running nollup in order to get HMR working for my CSS and Javascript.
I always get this output in the terminal whatever config I'm using (tried many, from some other repos, etc). The only way for me to get it working is by using the examples as it from the examples
folder of this repo, which calls the cli from a javascript file. When I try to use the nollup -c
command, that's when issues are coming by.
> npm run dev
> [email protected] dev /Users/user/Desktop/Rollup
> nollup -c --hot --port 3000
Listening on http://localhost:3000
Compiled in 944ms.
Compiled in 441ms.
^C%
Also the node
process in my Activity monitor goes off the roof with at least 300% CPU.
This is my package.json
{
"name": "test-nollup",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"build": "cross-env NODE_ENV=development nollup -c nollup.config.js -w --hot --content-base build --port 3000 --verbose",
"dev": "nollup -c --hot --port 3000"
},
"dependencies": {
"normalize.css": "^8.0.1"
},
"devDependencies": {
"@babel/core": "^7.8.3",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.8.3",
"@babel/preset-env": "^7.8.3",
"@babel/runtime": "^7.8.3",
"@rollup/plugin-commonjs": "^11.0.1",
"@rollup/plugin-node-resolve": "^7.0.0",
"@rollup/plugin-replace": "^2.3.0",
"autoprefixer": "^9.7.4",
"cross-env": "^6.0.3",
"eslint-config-standard": "^14.1.0",
"eslint-plugin-import": "^2.20.0",
"eslint-plugin-node": "^11.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"node-sass": "^4.13.1",
"nollup": "^0.10.2",
"postcss": "^7.0.26",
"postcss-banner": "^3.0.1",
"postcss-preset-env": "^6.7.0",
"rollup": "^1.29.0",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-banner": "^0.2.1",
"rollup-plugin-browsersync": "^1.1.0",
"rollup-plugin-bundle-html": "^0.2.2",
"rollup-plugin-clear": "^2.0.7",
"rollup-plugin-dev": "^1.1.1",
"rollup-plugin-eslint": "^7.0.0",
"rollup-plugin-hot-css": "^0.0.6",
"rollup-plugin-postcss": "^2.0.3",
"rollup-plugin-serve": "^1.0.1",
"rollup-plugin-terser": "^5.2.0"
},
"browserslist": [
"> 0.5%",
"last 2 versions",
"not dead"
]
}
and my rollup.config.js
import resolve from '@rollup/plugin-node-resolve'
import replace from '@rollup/plugin-replace'
import commonjs from '@rollup/plugin-commonjs'
import babel from 'rollup-plugin-babel'
import devserver from 'rollup-plugin-dev'
import browsersync from 'rollup-plugin-browsersync'
import postcss from 'rollup-plugin-postcss'
import clear from 'rollup-plugin-clear'
import html from 'rollup-plugin-bundle-html'
import banner from 'rollup-plugin-banner'
import { terser } from 'rollup-plugin-terser'
import { eslint } from 'rollup-plugin-eslint'
import pkg from './package.json'
// import settings from './settings.json'
// Define environment and things
const mode = process.env.NODE_ENV
const watch = process.env.ROLLUP_WATCH
const dev = mode === 'development'
const workdir = dev ? 'build' : 'dist'
// Rollup config
export default {
input: 'src/main.js',
output: {
dir: dev ? 'build' : 'dist',
entryFileNames: '[name]-[hash].js',
chunkFileNames: '[name]-[hash].js',
sourcemap: dev,
format: 'cjs'
},
// Plugins
plugins: [
// Clean
// clear({
// targets: [ workdir ],
// watch: true
// }),
// Serve
// dev && watch && devserver({
// port: 3100,
// dirs: [ workdir ],
// basePath: '/'
// }),
// dev && watch && browsersync({
// port: 3000,
// proxy: 'http://localhost:3100',
// open: false,
// notify: false
// }),
// PostCSS with SASS/SCSS/Stylus
// postcss({
// extract: true,
// sourceMap: dev
// }),
// Javascript
// replace({
// 'process.browser': true,
// 'process.env.NODE_ENV': JSON.stringify(mode)
// }),
// resolve({
// browser: true
// }),
// commonjs(),
// eslint({
// exclude: ['**/*.scss', 'node_modules/**']
// }),
// babel({
// extensions: ['.js', '.mjs', '.html'],
// exclude: ['node_modules/**'],
// runtimeHelpers: true
// }),
// Build
// html({
// template: 'src/template.html',
// dest: workdir,
// filename: 'index.html'
// }),
// !dev && terser({
// module: true,
// output: {
// comments: false
// }
// }),
// !dev && banner(`${pkg.name} v${pkg.version}\nBy ${pkg.author.name}\n${pkg.author.url}`)
]
}
Am I missing something ? ๐คช
Some advantages:
This would add support for more ways to configure nollup:
nollup
property in package.json
.nolluprc
file in JSON or YAML format.nolluprc.json
file.nolluprc.yaml
, .nolluprc.yml
, or .nolluprc.js
filenollup.config.js
file exporting a JS objectIt is widely adapted; used by 3.3m github repositories.
It has a documented order in which it will look for configuration.
Starting from process.cwd()
it will look for:
package.json
propertyJSON
or YAML
, extensionless "rc file".json
, .yaml
, .yml
, or .js
..config.js
CommonJS moduleThis should be backwards compatible with the current implementation where the .nolluprc
file has precedence over the nolluprc.js
file:
Lines 93 to 97 in 1411a03
Is there a specific reason the current implementation loads the configuration synchronously (i.e. using
fs.existsSync
andfs.readFileSync
)?
Could be replaced with
const cosmiconfigResult = require('cosmiconfig').cosmiconfigSync('nollup').search();
if (cosmiconfigResult && cosmiconfigResult.config) {
options = Object.assign({}, options, cosmiconfigResult.config);
}
cosmiconfig can be used synchronously as well as asynchronously.
See https://github.com/davidtheclark/cosmiconfig for more information.
Hi PrpsRyuu,
This stuff looks quite cool. But I'm a little confused, rollup
doesn't do many optimisations in dev mode, too. Why is nollup
faster than rollup
dev mode?
Using dynamic imports produces following error:
{ SyntaxError: 'import' and 'export' may only appear at the top level (29:2)
at _class.pp$4.raise (<project>/node_modules/nollup/node_modules/acorn/dist/acorn.js:2825:15)
at _class.pp$1.parseStatement (<project>/node_modules/nollup/node_modules/acorn/dist/acorn.js:859:18)
at _class.parseStatement (<project>/node_modules/acorn-dynamic-import/lib/index.js:63:118)
at _class.pp$1.parseBlock (<project>/node_modules/nollup/node_modules/acorn/dist/acorn.js:1161:23)
at _class.pp$1.parseStatement (<project>/node_modules/nollup/node_modules/acorn/dist/acorn.js:845:36)
at _class.parseStatement (<project>/node_modules/acorn-dynamic-import/lib/index.js:63:118)
at _class.pp$1.parseIfStatement (<project>/node_modules/nollup/node_modules/acorn/dist/acorn.js:990:28)
at _class.pp$1.parseStatement (<project>/node_modules/nollup/node_modules/acorn/dist/acorn.js:834:33)
at _class.parseStatement (<project>/node_modules/acorn-dynamic-import/lib/index.js:63:118)
at _class.pp$1.parseTopLevel (<project>/node_modules/nollup/node_modules/acorn/dist/acorn.js:746:23)
pos: 924,
loc: Position { line: 29, column: 2 },
raisedAt: 930 }
ParseError: src/index.tsx
Error: SyntaxError: 'import' and 'export' may only appear at the top level (29:2)
import('react-axe')
^
at bundle (<project>/node_modules/nollup/lib/index.js:393:19)
at process._tickCallback (internal/process/next_tick.js:68:7)
Possibly related to acornjs/acorn#809
I got several errors using React-Color and Material-UI. I find some solutions for MUI styling, but with React-Color no ways :-(
I got a TypeError: _common.ColorWrap is not a function
when using any React-Color pickers.
Very hard to debug as you are using eval and I get an infinite loop with 'React Dev Tools'...
The error is line 208 in Twitter.js component of React-Color:
exports.default = (0, _common.ColorWrap)(Twitter);
_common.ColorWrap is undefined.
I use my rollup-react-app template for the test. And I only add a React-Color Twitter component to the App to reproduce the bug.
I don't know if there are any limitations preventing this, but it would be great to allow ES6 module imports/exports in rollup.config.js
.
Eg:
import plugin from 'rollup-plugin';
export default {};
as opposed to:
const plugin = require('rollup-plugin');
module.exports = {};
I've just started using nollup and I need to rewrite my config so it's compatible.
Hi.
Without really knowing how possible this is, based on how nollup works - is it possible / are there any plans for nollup to expose an API matching Rollup's API?
The reason being is that we're toying with the possiblity of using nollup
for development mode in Sapper / Svelte apps to speed up the developer feedback loop, but currently I've not been able to get too far due to the lack of a compatible API.
Thread is here sveltejs/sapper#1207 (comment)
I keep my build target folder as a subfolder of the main project. I start nollup from the main project folder, so nollup watches the build target as well which results in constant recompile.
In rollup there is a config
watch: {
exclude: 'dist'
}
This seems a basic requirement to me. Am I missing something maybe?
Bear with me...
If I have 2 dynamic imports in my entry points, and both of them import another module, that itself imports another module... And if only the 2nd dynamic import is actually executed, then the transitive dep module is missing, which results in the following error:
Uncaught (in promise) TypeError: modules[number] is not a function
I've pushed a reproduction case on the bug-shared-dynamic-imports branch of my playground repo of the moment.
To illustrate, here what a simple main.js
would look like:
if (false) import('./dyn1.js')
import('./dyn2.js')
Where dyn1.js
and dyn2.js
would both have this code:
import dep from './dep.js'
console.log(dep)
And dep.js
itself would be:
import sub from './sub.js'
export default sub
It's this sub.js
module that would be missing from the dyn2.js
"chunk". It would be present in dyn1.js
, but since it is skipped at runtime... Still missing.
The error comes when I try to import the npm package eddystone-url-encoding
:
(node:1988) UnhandledPromiseRejectionWarning: Error: "version" is a required argument.
--- C:\projects\sample-project\node_modules\eddystone-url-encoding\lib\prefixes.json
--- C:\projects\sample-project\node_modules\eddystone-url-encoding\lib\decode.js
--- C:\projects\sample-project\node_modules\eddystone-url-encoding\index.js
--- C:\projects\sample-project\src\utils\Beacon\Eddystone.ts
I'm assuming that the error is from the json plugin and not because the library is a CommonJS module, but, of course, I could be wrong.
So close to finally having nollup up and running with HMR! This is my first project where I've attempted to use HMR by the way, so I'm sure there are simple things I'm overlooking.
I'm calling nollup like this: nollup -c --hot
The bundle builds without errors and my app loads. But HMR isn't working and this is in the console:
WebSocket connection to 'ws://__hmr/' failed: Error during WebSocket handshake: Unexpected response code: 200
and the line that's throwing this error:
var ws = new WebSocket('ws://' + window.location.host + '/__hmr');
Any suggestions? Should I be filling something in for --hmr-host
?
Thank you!
React has new official way to do HMR called fast refresh
Integration with bundler involves few steps (outlined in this comment)
This does do everything that is needed (I think) in rollup plugin except point 3 which is implemented using new hook.
Add new hook nollupModuleWrap
which can add code around module.__impl
call in lib/index.js
(see commit linked above for implementation)
I have a working setup with rollup and typescript. I just added nollup
and changed my dev
setup to this
rimraf public && cross-env NODE_ENV=development nollup -c --hot --content-base public
I get this error which I really don't understand.
ParseError: ndex.js
Error: Unknown object type "set iterator"
at bundle (/workspace/phaser3-rollup-typescript/node_modules/nollup/lib/index.js:508:15)
at async generateImpl (/workspace/phaser3-rollup-typescript/node_modules/nollup/lib/index.js:693:21)
You may test by running yarn dev
command here. I have the repository here:
I'm trying to make react-hot-loader in my project work.
I'll be glad to improve nollup
to achieve it as well.
please take a look:
https://github.com/welldone-software/why-did-you-render/tree/react-hot-loader
react-hot-loader
tree
I followed the steps suggested but it doesn't seem to work or error.
I'll be glad for someone suggesting what's the problem there.
In the end we will have a React project example (yey! :D )
Circular dependencies are not caught as an error and continue in an infinite loop.
This line, shouldn't it be every
instead of some
? We need all impacted branches to independently accept the change, don't we?
For me none of the examples work
I cloned the repo, went into an example folder and did
npm install
npm run start
The compile failed with an error:
> @ start /Users/marko/git/nollup/examples/example-circular
> cross-env NODE_ENV=development node ../../lib/cli.js -c --content-base public --port 9001 --hot
internal/modules/cjs/loader.js:651
throw err;
^
Error: Cannot find module 'express'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:649:15)
at Function.Module._load (internal/modules/cjs/loader.js:575:25)
at Module.require (internal/modules/cjs/loader.js:705:19)
at require (internal/modules/cjs/helpers.js:14:16)
at Object.<anonymous> (/Users/marko/git/nollup/lib/cli.js:5:15)
at Module._compile (internal/modules/cjs/loader.js:799:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:810:10)
at Module.load (internal/modules/cjs/loader.js:666:32)
at tryModuleLoad (internal/modules/cjs/loader.js:606:12)
at Function.Module._load (internal/modules/cjs/loader.js:598:3)
After that I tried
nollup -c
which did compile, but the page would give an error in the browser console:
Refused to load the font '<URL>' because it violates the following Content Security Policy directive: "default-src 'none'". Note that 'font-src' was not explicitly set, so 'default-src' is used as a fallback.
localhost/:1 Refused to load the image 'http://localhost:8080/favicon.ico' because it violates the following Content Security Policy directive: "default-src 'none'". Note that 'img-src' was not explicitly set, so 'default-src' is used as a fallback.
Am I missing something?
great work , thank you. here's a working typescript example with the proper file extension resolving and what not, pretty annoying to get right with rollup and babel usually. threw in a random hooks test to see how that went, had to add 'createContext' to the named exports. i wish rollup had a way to disable named imports and always use the default export , maybe it does but i havn't figured out a way to so
We currently use Typescript/Rollup to generate and bundle our code. The typescript target ES is ES2018.
We do not use Babel
anywhere in the build pipeline, since typescript is enough. Is it possible to use react-hot-loading with nollup
without introducing Babel ?
If it absolutely needs to be, what is the minimal footprint it can have with no effect on build times.
Also, it will be great if we could post an example with Typescript and hot-loading.
When : I switch from a branch or pull some code and Nollup is running
(node:4268) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, lstat '/.../RollupReactApp/.git/HEAD.lock'
at Object.lstatSync (fs.js:939:3)
at FSWatcher.onChange (/.../RollupReactApp/node_modules/nollup/lib/dev-middleware.js:160:20)
at FSWatcher.emit (events.js:321:20)
at FSWatcher.<anonymous> (/.../RollupReactApp/node_modules/chokidar/index.js:199:15)
at FSWatcher._emit (/.../RollupReactApp/node_modules/chokidar/index.js:241:5)
at FSWatcher.<anonymous> (/.../RollupReactApp/node_modules/chokidar/lib/fsevents-handler.js:210:14)
at addOrChange (/.../RollupReactApp/node_modules/chokidar/lib/fsevents-handler.js:216:7)
at /.../RollupReactApp/node_modules/chokidar/lib/fsevents-handler.js:226:39
at /.../RollupReactApp/node_modules/graceful-fs/graceful-fs.js:57:14
at FSReqCallback.oncomplete (fs.js:154:23)
Instead it should be silent or display a warning ?
Also why is it listening to .git folder ?
From Rollup's docs:
Note: While in watch mode, the ROLLUP_WATCH environment variable will be set to "true" by Rollup's command line interface and can be checked by plugins and other processes.
That would be great to have something similar with Nollup (e.g. NOLLUP or NOLLUP_WATCH).
It would allow to transparently adapt the behavior of a plugin without requiring the user to alter their Rollup config. Or to use workarounds like resolveId
instead of resolve
.
Hello,
I've just installed nollup 0.7.6 and attempted to run it with a simple nollup -c
My npm output is:
/node_modules/nollup/lib/impl/AcornParser.js:43
let parser = acorn.Parser.extend(ImportMetaPlugin);
^
TypeError: acorn.Parser.extend is not a function
at Object.<anonymous> (/node_modules/nollup/lib/impl/AcornParser.js:43:27)
at Module._compile (internal/modules/cjs/loader.js:707:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:718:10)
at Module.load (internal/modules/cjs/loader.js:605:32)
at tryModuleLoad (internal/modules/cjs/loader.js:544:12)
at Function.Module._load (internal/modules/cjs/loader.js:536:3)
at Module.require (internal/modules/cjs/loader.js:643:17)
at require (internal/modules/cjs/helpers.js:22:18)
at Object.<anonymous> (/node_modules/nollup/lib/impl/ImportExportResolver.js:11:19)
at Module._compile (internal/modules/cjs/loader.js:707:30)
Really looking forward to using this. Any help is much appreciated!
When I try to run nollup
with the reccommended setup for react-refresh
I get this error on one of my modules:
ParseError: Users/ashish/thoughtspot/node_modules/use-http/dist/index.js
TypeError: Cannot read property 'length' of undefined
at /Users/ashish/thoughtspot/blink-v2/node_modules/nollup/lib/impl/utils.js:72:65
at Array.forEach (<anonymous>)
at combineSourceMapChain (/Users/ashish/thoughtspot/blink-v2/node_modules/nollup/lib/impl/utils.js:67:22)
at Object.transform (/Users/ashish/thoughtspot/blink-v2/node_modules/nollup/lib/impl/PluginLifecycle.js:217:11)
at async parse (/Users/ashish/thoughtspot/blink-v2/node_modules/nollup/lib/index.js:51:31)
at async parse (/Users/ashish/thoughtspot/blink-v2/node_modules/nollup/lib/index.js:116:17)
The command fails and does not continue after this, just keeps printing the above error. If I comment the above import out, it fails at some other file.
I'm attempting to modify your example to work with React + Babel, in anticipation of being able to use HMR.
However I receive TypeError: modules[number] is not a function
errors in the browser console upon compilation (the compile task displays the "Compiled in xxxms" message however).
When I add a console.log(number)
in the require function nollup creates, it will iterate over the numbers 0, 1 then print object-assign
When inspecting sources I find dependencies of React haven't been transformed:
var _assign = require('object-assign');
var checkPropTypes = require('prop-types/checkPropTypes');
I've linked below a minimum viable repro:
I test react-three-fiber with my rollup-react-app
But the first example in README.md is crashing:
After some investigation to check if i need some other modules, I think it is a bug in Nollup not importing correctly react-reconcilier
.
I can't seem to get typescript to work. I've tried both these plugins:
https://github.com/rollup/rollup-plugin-typescript
https://github.com/ezolenko/rollup-plugin-typescript2/
Neither appear to transpile the code.
SyntaxError: Unexpected token (6:5)
type thing = number
^
Trace: Error trace
at bundle (/Users/michaelorenstein/Projects/nollup/lib/index.js:496:17)
at process._tickCallback (internal/process/next_tick.js:68:7)
at Function.Module.runMain (internal/modules/cjs/loader.js:745:11)
at startup (internal/bootstrap/node.js:279:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:696:3)
Building them manually with my usual config, and with the build script provided both work.
It's just the 'start' command that seems to have issues.
I've branched off as far as I got:
https://github.com/Mike-Dax/nollup/tree/typescript-example/examples/typescript-react
Thank you for your help.
Nollup at the moment does not support circular dependencies.
Webpack supports circular dependencies by implementing the "live binding" specification of ES Modules. It accomplishes this by replacing all import variables with an object, and accessing a special property on the object with a getter that gets the latest value.
// In the exported file, if we exported a variable called "number",
// it will add this to the exports instead of "number" directly.
Object.defineProperty(__webpack_exports__, "a", {
configurable: false,
enumerable: true,
get: () => number
});
// Import variables are replaced to this renamed variable.
var __WEBPACK_IMPORTED_MODULE_0__a__ = __webpack_require__(0);
// All references to the imported variable must be replaced and does a get
// on the specially defined property. This property will return the latest value.
console.log(__WEBPACK_IMPORTED_MODULE_0__a__["a" /* number */]);
I don't really want to implement this because of the following reasons:
Significant complexity, would have to traverse the entire syntax tree, figured out if the imported variable was used, and replace it with the objects. This can introduce a significant performance penalty, and might not be entirely reliable unless all possibilities have been considered (eg. what if a local variable by the same name as an import is declared?)
Breaks debugging symbols. By swapping out import variables with objects, it breaks debugging because the variables you see in the code are not the variables that are outputted. So if you want to watch variables, or test stuff in the console, you have to use the transpiled variable name instead which can be confusing.
Live bindings is a rarely used feature. Should the live-binding specification be supported for a rare circular use case, and in those situations where it is a use case, is usually a code smell and can be refactored to not be circular? Should performance and debugging be hit where other workarounds may exist?
Would love to hear people's thoughts on this. I have no plans to implement this feature, but it is open to anyone who wants to try solve it.
Rollup is explicit about ignoring falsy plugins:
See Using plugins for more information on how to use plugins and Plugins on how to write your own (try it out, it's not as difficult as it may sound and very much extends what you can do with Rollup). For plugins imported from packages, remember to call the imported plugin function (i.e. commonjs(), not just commonjs). Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins.
(see https://rollupjs.org/guide/en/#plugins)
I quickly tried nollup on our project now, and noticed that it stumbled over such a situation. A quick patch as below made it go further, but then gets stuck on other, more problematic uses in our setup.
As this is only lightly tested: Not a PR, but a starting point of a patch instead:
diff --git a/lib/cli.js b/lib/cli.js
old mode 100644
new mode 100755
diff --git a/lib/impl/NollupContext.js b/lib/impl/NollupContext.js
index f755836..d989aa7 100644
--- a/lib/impl/NollupContext.js
+++ b/lib/impl/NollupContext.js
@@ -39,6 +39,8 @@ module.exports = {
create: function (options) {
if (!options.plugins) {
options.plugins = [];
+ } else {
+ options.plugins = options.plugins.filter(plugin => Boolean(plugin));
}
if (!options.output) {
Hi, I just tried using nollup (0.11.1
) in my project but when I run nollup -c with a rollup.config.js that works and the following .nolluprc.js
module.exports = {
hot: true,
contentBase: './public'
};
I get the following output :
$ nollup -c
Listening on http://localhost:8080
LiveReload enabled
Compiled in 3551ms.
Compiled in 150ms.
Compiled in 90ms.
Compiled in 108ms.
Compiled in 69ms.
Compiled in 86ms.
Compiled in 78ms.
Compiled in 69ms.
Compiled in 71ms.
Compiled in 66ms.
Compiled in 70ms.
....
and the list goes on. even if I do not do any editing
Any idea?
Rollup just released new option for plugins named syntheticDefaultExports. It allows for better implementation of commonjs plugin without need to manually specify named exports which I found to be the biggest obstacle to using rollup.
Link to rollup PR: rollup/rollup#3295
Creating this issue only to bring this option to your attention. Thanks for awesome project.
I'm assuming this is an issue of raw chokidar events being different across platforms. I'm running MacOS High Sierra, 10.13.6.
When I inspect the type, the string provided is 'modified' instead of 'change', and the details contains 'path' instead of 'changedPath'.
I've created a PR that uses the normalised add and change events instead if that's an acceptable fix.
Aaaah, I'm too excited about this!
I've look at how Webpack Dev Server does it: https://github.com/webpack/webpack-dev-server/blob/master/lib/Server.js#L178. They use a compiler hook and write errors on the WS as 'error' event. Apparently, the WS client then publishes this with a custom event on window, for consumption by "plugins". In those, I bet there is the one implementing the module.hot
protocol. On the other hand, the WS client does process the compile error & implement the overlay itself.
I'm not a fan of how this is hard to track...
So! I couldn't resist to see how my Svelte HMR would look with compile error reporting, so I spun a test implementation around your idea of module.hot.compile
: master...rixo:compile-error-reporting
And here's the code using it: https://github.com/rixo/rollup-plugin-svelte-hmr/blob/master/index.js#L77 (and the demo, if you're into Svelty things -- I hooked it up to my fork for now).
(It looks very well! That's just some very very preliminary very early impression but the whole thing seems flawless... On the paper, it might be better than React Fast Refresh. LOL. Svelte's awesome.)
Anyway, to us... As you can see, I didn't do module.hot.compile
but window.__hot.addErrorHandler
. That's because I realized that when we get a compile error, it can't be targeted at one module, the whole bundle has to be dead, right?
Were you thinking of propagating the bundle error to all module instances (i.e. call every module.compile
callback)?
If so, this way would be very impractical to manage something like an error overlay. We only want to control it from a central location that does not get affected by code reload. We want it central because it has to manage singleton assets, e.g. its overlay's DOM element. Like the WS itself needs to be central to manage its connection.
The questions I've asked myself when doing this:
Starting from the WS message that is written by the server: should it contains errors
or only allow for one single error? Is it possible to somehow have multiple compile errors simultaneously?
Should the server (or the WS client) emit null
when the compile error is cleared (i.e. on successful compile)? That makes consumer implementation more straightforward, at least.
Also, if we agree that the addErrorHandler
API should be central rather than on module
, how to expose it to consumer? I guess window.__hot
is supposed to be private? Maybe pass it to nollupBundleInit
? That's more restricting but it might be cleaner. That would make nollupBundleInit
callbacks the only possible place you have to search to find HMR/WS client related code in plugins.
Ah! And just to mention it, what would be the final touch for error reporting would be that the server manages to deliver something anyway when it starts with an initial compile error. Maybe send a blank script with just the HMR clients (nollupBundleInit
). This way we could display the initial error in the browser, like WDS (it does a full reload when the error is fixed). Don't know how doable that would be. But that would really be the icing on the cherry anyway.
So, what do you think?
We have a couple of libraries linked as globals because Rollup hates them. Specifically, the AWS JS sdk stuff.
My rollup.config.js has them as:
globals: {
'aws-wrapper': 'awsWrapper',
'AWS': 'AWS',
},
Nollup assumes that import Cognito from 'aws-wrapper';
means to import from a file named aws-wrapper.js
in the current directory. This is incorrect and all references to Cognito
should be replaced with awsWrapper.default
.
I'm sorry to keep bugging you with all my issues, but I'd really like to bring Nollup to feature parity with Rollup, at least for the official Svelte template and simple cases, and make it the preferred solution for Svelte HMR. I just love Nollup's speed. Sometimes, I wonder if an update has applied because it happened in the time interval while my eyes were jumping from the left side of my screen to the right (editor -> browser)...
So, I've got a problem in my template because I haven't enough control (or maybe understanding) on the URL of the files generated by the bundling.
This problem is the reason why I have this special handling of output.file
for Nollup. Note that this workaround doesn't work anymore with 0.9.0
.
Say I have output.file: 'public/build/bundle.js'
.
In versions before 0.9.0
, Nollup will use the full path as URL, e.g. http://localhost:8080/public/build/bundle.js
.
In 0.9.0
, it only uses the basename, e.g. http://localhost:8080/bundle.js
.
What I really want is http://localhost:8080/build/bundle.js
. That's what I get if I build this with Rollup and launch a http server from the public
directory. The file gets written in public/build/bundle.js
, and the server sees build/bundle.js
as the URL.
So I would expect Nollup with contentBase: 'public'
to produce the same URL.
For illustration, I've hacked something that works for me.
I think reusing contentBase
is the correct behaviour because, like I said, that's what you get if you use Rollup + a web server. So Nollup, to align with Rollup, would write the "virtual" (in-memory) file to public/build/bundle.js
; and, if it serves (contentBase) from dir public
, then it should see the URL as build/bundle.js
. Is this a good idea to change the meaning of an existing variable though?
Another question is: what to do with files that are written outside of the public directory? For example, if I have output.file: 'dist/bundle.js'
, but contentBase: 'public'
. Hmm. In this case, my implementation just use the full path of the file as URL, because I don't see any other solution.
With output.dir
, I think Nollup's behaviour is aligned with Rollup, as a bundler. However, as server, it makes the assumption that the output dir is also the public dir, which might not hold in every project. I guess most cases can be handled by tweaking entryFileNames
, but I think that these settings should live in Nollup's config, not Rollup's. They are related to serving, not bundling.
I'm not too sure what the solution should look like. Should it be based on contentBase
or some new specific options?
With following plugin:
const fs = require('fs')
const { promisify } = require('util')
const path = require('path')
function url({ exts = ['.svg', '.png', '.jpg', '.gif'] } = {}) {
return {
name: 'rollup-plugin-custom-url',
async load(id) {
if (exts.some(ext => id.endsWith(ext))) {
const ref = this.emitFile({
type: 'asset',
source: await promisify(fs.readFile)(id, { encoding: 'binary' }),
name: path.basename(id),
})
return 'export default import.meta.ROLLUP_FILE_URL_' + ref
}
return null
},
}
}
And code importing for example .png file:
import url from './logo.svg'
const el = document.createElement('img')
el.src = url
document.body.appendChild(el)
I get following error
{ SyntaxError: Unexpected token (1:21)
at Parser.pp$4.raise (<project>/node_modules/acorn/dist/acorn.js:2836:15)
at Parser.pp.unexpected (<project>/node_modules/acorn/dist/acorn.js:689:10)
at Parser.pp$3.parseExprImport (<project>/node_modules/acorn/dist/acorn.js:2271:12)
at Parser.pp$3.parseExprAtom (<project>/node_modules/acorn/dist/acorn.js:2254:21)
at Parser.pp$3.parseExprSubscripts (<project>/node_modules/acorn/dist/acorn.js:2089:21)
at Parser.pp$3.parseMaybeUnary (<project>/node_modules/acorn/dist/acorn.js:2066:19)
at Parser.pp$3.parseExprOps (<project>/node_modules/acorn/dist/acorn.js:2010:21)
at Parser.pp$3.parseMaybeConditional (<project>/node_modules/acorn/dist/acorn.js:1993:21)
at Parser.pp$3.parseMaybeAssign (<project>/node_modules/acorn/dist/acorn.js:1968:21)
at Parser.pp$1.parseExport (<project>/node_modules/acorn/dist/acorn.js:1431:33) pos: 21, loc: Position { line: 1, column: 21 }, raisedAt: 22 }
ParseError: src/img/logo.svg
Error: SyntaxError: Unexpected token (1:21)
export default import.meta.ROLLUP_FILE_URL_logo_svg
^
at parse (<project>/node_modules/nollup/lib/index.js:93:23)
This was mostly experiment in writing simple replacement for rollup-plugin-url
So, this is a bit of a follow up to #56.
I am encountering issues with URLs in several projects I'm trying to Nollupize. I've identified 3 causes:
output.dir
are discarded from URL, which defers from Rollupdist
and public
folder, and I need URLs from Nollup to be adjusted accordinglyI've created a repo to illustrate and help diagnostic the issues: https://github.com/rixo/nollup-test-case-output-dir
The problems are described in detail in the readme.
I've gone fancy and used a test runner that is not yet very stable, especially with Windows... Let me know if it doesn't work for you, I'll try to simplify the setup.
export let abc = 123;
console.log(abc);
throws:
(node:704496) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'split' of undefined
Hi! I'm trying to implement Svelte HMR over nollup. Initial trial went way over expectations. (Initial tests with 3 lines of code suggest it might be one bazillion times faster than Webpack, but it's too early to tell.)
So now I'd want to integrate the nollup setting to my HMR test suite, that only supports Webpack for now. (The meat of the Webpack integration is in a sub project.)
For that, the test harness needs some special programmatic control over the dev server that I believe is not entirely possible currently with nollup. What is needed specifically is:
to control a virtual input filesystem (to be able to generate test source files in memory)
to control / mock the file watcher
to know, on the server side, when bundling is complete / dev server ready (for the initial page load)
to know when a HMR update has completed on the client side (in order to run the assertions only when it's ready)
and also on the client side, after initial page load to know when the HMR client is ready (~WS connected) -- I don't really know how important this is with nollup, but it caused race conditions in the tests with Webpack
Point 4 can already be done by monitoring [HMR]
messages in the console.
For point 5 however, there's no initial console message in nollup, which would be great to completely eliminate possibilities of race. For example, a greeting message here would do the trick nicely.
Point 3 can probably be done in a rollup plugin.
However, for the first 2 points, I see no ways to hook into nollup currently. I have experimented with passing as options the chokidar
and fs
objects that are used here and here, and it seems to do the trick. That's quite fragile because it tightly couples the test driver to nollup's internals but, given the use case, that could be good enough for me. The rest can be done via rollup plugin, I think.
So I wanted to know what you think about this. Can you suggest better solutions, maybe? And would be you be interested in adding this kind of support to nollup? I can work on a PR if needed.
Given example from rollup docs
function myExample () {
return {
name: 'my-example', // this name will show up in warnings and errors
resolveId ( source ) {
if (source === 'virtual-module') {
return source; // this signals that rollup should not ask other plugins or check the file system to find this id
}
return null; // other ids should be handled as usually
},
load ( id ) {
if (id === 'virtual-module') {
return 'export default "This is virtual!"'; // the source code for "virtual-module"
}
return null; // other ids should be handled as usually
}
};
}
module.exports = ({
input: 'virtual-module', // resolved by our plugin
plugins: [myExample()],
output: [{
file: 'bundle.js',
format: 'esm'
}]
});
nollup fails because it does not call resolveId for entrypoint
This is low-priority issue because it is really easy to work around but i figured it would be good to report.
Hi there,
I was trying this out, but it doesn't seem to support configs with arrays as I am receiving this error:
UnhandledPromiseRejectionWarning: Error: Input option not defined
Is there any particular reason we cannot support an array of configs? If not I am happy to do a PR. Thanks.
Use case: Svelte components can include CSS.
<script>
import { name } from './foo.js'
</script>
<p> I am {name}.<p>
<style>
p { color: green; }
</style>
When people are fine tuning their CSS, they're likely to trigger a lot of HMR updates and, if I can tell whether this is just a CSS change, I can skip replacing the whole component and get away with just switching a stylesheet in the browser. This is far better because replacing a component always comes with a risk of HMR quirk, while switching a stylesheet is essentially bulletproof...
But I can only do that safely if I'm sure that the HMR update comes from a change to the component file itself. In the example above, if the component's accept
handler is run because it has bubbled from ./foo.js
, I do have to recreate the component to reflect the change.
Problem: there's no way currently to tell if an accept handler is run because its module has changed or if it is because an HMR update has bubbled from a dependency, is there?
Suggested solution: in my own hot plugin, I'm passing an argument to the accept handlers with the info.
import.meta.hot.accept(({ hasChangedDeps }) => {
if (!hasChangedDeps && onlyCss) onlyInjectCss()
...
})
I absolutely don't recommend the name hasChangedDeps
because each time I go back to this code it takes me some time to figure out what it means already. Maybe bubbled
would be good? But the general strategy works well.
That being said, any way to tell if the update is direct or bubbled from an accept handler would be ok for my use case.
the demo is on the branch
https://github.com/welldone-software/why-did-you-render/tree/support-styled-components
run yarn
run yarn start
open localhost:3003
as i understood it is fixed on rollup-plugin-commonjs
v9:
rollup/rollup-plugin-commonjs#321
so there is probably something to add to custom-rollup-plugin-commonjs
Can be seen in my svelte template. On the branch repro-nollup-sourcemaps
, I have removed all my hot stuff from the Rollup config to reduce debugging noise.
I have put 2 debugger
in a svelte file to clearly illustrate the problem.
Run npm run dev
, and the debugger stops on the right mapped lines in the original svelte source.
Run npm run dev:nollup
and everything works but the sourcemaps are off.
Both commands serves the app on http://localhost:5000.
For a little background, I have recently produced a Svelte HMR demo with Snowpack that gives instant feedback over HMR in a project that loads 500 Svelte components on the index page. This has revived interest a little for Svelte HMR in the community. I had the idea to subject Nollup to the same test. Just as fast. Twice faster on full reloads (since Snowpack sends 500+ files to the browser). I'm particularly happy to confirm that Nollup rebuild time is not affected by the size of the project, like the no-bundle dev servers (but unlike Rollup unfortunately). And so all this got me motivated to turn back to Nollup and push it as the preferred HMR solution for Svelte projects. This sourcemap issue has been the main bother for me.
Hello,
I have my own in process dev server running (in asp.net core) website, it calls out to rollup to process files, and has a rudimentary browser reload based on signalr. I am now looking at adding HMR capability and have been looking at https://github.com/alexisvincent/systemjs-hmr
I have noticed that when calling rollup, it produces a bundle file, but I have no access to information about the "module names" that changed since last time. It seems if I wanted to trigger a reload of a hot module in the browser it would be helpful to atleast establish the module name that changed..
So this lead me to nollup
. Could nollup
help me here? I.e if I included a nollup plugin in the rollup build, could I collect information about module id's that have been changed? I would need to collect that information, so that my server could send that information to the browser to then trigger the reload of those modules in the browser.
I am pretty new to all this so I am very much just figuring all this out as I go ;-)
If I try to build project containing npm package [email protected]
it produces following errors:
ParseError: node_modules/subscriptions-transport-ws/dist/client.js
TypeError: Cannot read property 'type' of null
at walk (/home/isabella/Dokumenty/html/bookcity.live/frontend/node_modules/nollup/lib/impl/ImportExportResolver.js:255:26)
at process._tickCallback (internal/process/next_tick.js:68:7)
ParseError: node_modules/subscriptions-transport-ws/dist/client.js
TypeError: Cannot read property 'type' of null
at walk (/home/isabella/Dokumenty/html/bookcity.live/frontend/node_modules/nollup/lib/impl/ImportExportResolver.js:255:26)
at process._tickCallback (internal/process/next_tick.js:68:7)
at parse (/home/isabella/Dokumenty/html/bookcity.live/frontend/node_modules/nollup/lib/index.js:93:23)
at process._tickCallback (internal/process/next_tick.js:68:7)
Offending line in source
It happens on following code
this.client.onopen = function () { return __awaiter(_this, void 0, void 0, function () {
var connectionParams, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(this.status === this.wsImpl.OPEN)) return [3, 4];
this.clearMaxConnectTimeout();
this.closedByUser = false;
this.eventEmitter.emit(this.reconnecting ? 'reconnecting' : 'connecting');
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4, this.connectionParams()];
case 2:
connectionParams = _a.sent();
this.sendMessage(undefined, message_types_1.default.GQL_CONNECTION_INIT, connectionParams);
this.flushUnsentMessagesQueue();
return [3, 4];
case 3:
error_1 = _a.sent();
this.sendMessage(undefined, message_types_1.default.GQL_CONNECTION_ERROR, error_1);
this.flushUnsentMessagesQueue();
return [3, 4];
case 4: return [2];
}
});
}); };
Which apparently what tsc
generates from this source
Reproduction
git clone [email protected]:CodeWitchBella/nollup-reproduction.git
cd nollup-reproduction
npm ci
npx nollup -c
Reproduction is made as modified examples/example-react-hot-loader from this repo
Hi there,
My bundled file ends up running in an environment that has access to node modules. In one of my modules I have:
let spawn = require('child_process').spawn;
When running nollup -c
I get this error:
ParseError: child_process
Error: ENOENT: no such file or directory, open 'child_process'
at parse (/node_modules/nollup/lib/index.js:93:23)
at process.internalTickCallback (internal/process/next_tick.js:77:7)
I've tried setting preferBuiltins
to both true and false in the node resolve plugin options, but neither works.
Is this something that can be fixed?
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.