Namir Sayed-Ahmad Baraza
@namirsab [github|twitter]
namirsab@gmail.com
Introduction
Migrating a Package
Conclusions
As we know, javascript development is crazy
It's changing every day
$> meteor add username:packagename
Pros:
Cons:
$> npm install packagename [options]
Pros:
Cons:
"1.3 introduced npm install support along with ES2015 modules. With 1.4, we would like to transition the Meteor package ecosystem over entirely from Atmosphere to npm"
MDG in the Meteor Roadmap
From 1.2 to 1.3 with ES6 modules
const height = new ReactiveVar(window.outerHeight);
const width = new ReactiveVar(window.outerWidth);
const $window = $(window);
Meteor.startup(() => {
$window.resize(function() {
height.set(window.outerHeight);
width.set(window.outerWidth);
});
});
// Global Symbol necessary to export it
WindowState = {
isMaximized() {
const currentHeight = height.get();
const currentWidth = width.get();
const availHeight = screen.availHeight * 0.9;
const availWidth = screen.availWidth * 0.9;
return !(currentHeight < availHeight || currentWidth < availWidth);
},
height: () => height.get(),
width: () => width.get()
};
Original code
Original package.js
Package.describe({
name: 'qlp:qlp-window-state',
version: '0.0.1',
// Brief, one-line summary of the package.
summary: '',
// URL to the Git repository containing the source code for this package.
git: '',
// By default, Meteor will default to using README.md for documentation.
// To avoid submitting documentation, set this field to null.
documentation: 'README.md'
});
Package.onUse(function (api) {
api.versionsFrom('1.2.0.2');
api.use([
'ecmascript'
]);
// Packages for Client
api.use([
'jquery',
'reactive-var',
], 'client');
api.addFiles('client/WindowState.js', 'client');
// Export the Global Symbol we've defined in client/WindowState.js
api.export('WindowState');
});
import { ReactivVar} from 'meteor/reactive-var';
import { jQuery as $} from 'meteor/jquery'; // Note we import everything now
const height = new ReactiveVar(window.outerHeight);
const width = new ReactiveVar(window.outerWidth);
const $window = $(window);
Meteor.startup(() => {
$window.resize(function () {
height.set(window.outerHeight);
width.set(window.outerWidth);
});
});
// The symbol is not global anymore
const WindowState = {
isMaximized() {
const currentHeight = height.get();
const currentWidth = width.get();
const availHeight = screen.availHeight * 0.9;
const availWidth = screen.availWidth * 0.9;
return !(currentHeight < availHeight || currentWidth < availWidth);
},
height: () => height.get(),
width: () => width.get()
};
// We export it using ES6 exports
export {
WindowState
};
New Code
New package.js
Package.describe({
name: 'qlp:qlp-window-state',
version: '1.0.0',
// Brief, one-line summary of the package.
summary: '',
// URL to the Git repository containing the source code for this package.
git: '',
// By default, Meteor will default to using README.md for documentation.
// To avoid submitting documentation, set this field to null.
documentation: 'README.md'
});
Package.onUse(function (api) {
api.versionsFrom('1.3.2.4');
api.use([
'ecmascript'
]);
// Packages for Client
api.use([
'jquery',
'reactive-var',
], 'client');
// Now we export it with api.mainModule
api.mainModule('client/WindowState.js', 'client');
});
Warning:
Right now our package is not compatible with 1.2 and below
From 1.3 with ES6 modules to npm package
$> mkdir node_modules;
$> cd node_modules;
$> mkdir qlp-window-state
$> cd qlp-window-state && npm init
my-app/
node_modules/
package-name/
package.json
myCode.js
And now we can install dependencies directly with npm
$> meteor npm install jquery --save
Back to our example: package.json
{
"name": "qlp-window-state",
"version": "1.0.0",
"description": "Reactive Window State",
"main": "client/WindowState.js",
"author": "quantilope",
"license": "MIT",
"dependencies": {
"jquery": "^2.2.4"
}
}
Take a look to the dependencies...
Don't you miss something?
Packages hosted only on Atmosphere cannot be linked as dependencies of an npm package
But we can do a trick...
function importFromMeteorPackage(packageName, symbolName) {
if(!Package) {
throw new Error(`This package is only working inside Meteor apps`);
}
else if (!Package['reactive-var']) {
throw new Error(`${symbolName} is required, add it with "meteor add ${packageName}"`);
}
else {
return Package[packageName][symbolName];
}
}
Let's take a look to the code
import $ from 'jquery'; //jquery now comes from npm
const ReactiveVar = importFromMeteorPackage('reactive-var', 'ReactiveVar');
const height = new ReactiveVar(window.outerHeight);
const width = new ReactiveVar(window.outerWidth);
const $window = $(window);
// No more Meteor.startup. We don't want more Meteor dependecies.
$(document).ready(function () {
$window.resize(function () {
height.set(window.outerHeight);
width.set(window.outerWidth);
});
});
const WindowState = {
isMaximized() {
const currentHeight = height.get();
const currentWidth = width.get();
const availHeight = screen.availHeight * 0.9;
const availWidth = screen.availWidth * 0.9;
return !(currentHeight < availHeight || currentWidth < availWidth);
},
height: () => height.get(),
width: () => width.get()
};
// npm module.exports instead of export from js
module.exports = {
WindowState
}
New Code
Uncaught SyntaxError: Unexpected token import
In your package folder:
{
"name": "qlp-window-state",
"version": "1.0.0",
"description": "Reactive Window State",
"main": "./distribution/WindowState.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "babel client --presets babel-preset-es2015 --out-dir distribution"
},
"author": "quantilope",
"license": "MIT",
"dependencies": {
"jquery": "^2.2.4"
},
"devDependencies": {
"babel-cli": "^6.9.0",
"babel-preset-es2015": "^6.9.0"
}
}
New package.json
Now run npm run build
and everything works!
Checkout this branches