DEV Community

loading...
Cover image for Make service injection private

Make service injection private

Domenik Reitzner
・2 min read

This is part five of seven.

Prerequisits

This part is very specific to how this project is set up and depends on what has been done in step four.

Our components/directives/services use the class syntax and bind the injected service to the class to keep the scope clean from services.

class AwesomeComponent {
    constructor(MyService) {
        Object.assign(this, {MyService});
    }
}
Enter fullscreen mode Exit fullscreen mode

The bundle served

After the build process our code will look something like this:

var AwesomeComponent = function() {
    AwesomeComponent.$inject = ['MyService'];

    function AwesomeComponent(MyService) {
        _classCallCheck(this, AwesomeComponent);
        Object.assign(this, {
            MyService: MyService
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

Some of you might already see the potential her 😉

The way to privatization

In the last part we have looked at the possibility to minify our private methods (in my project I declare them with _ in the beginning). As our services are exclusively used within the component/directive/service, we could argue that they are injected private Methods.

So the way to optimize our class would be:

class AwesomeComponent {
    constructor(MyService) {
        Object.assign(this, {
            _MyService: MyService,
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

It would be really boring and prone to mistakes to do all those changes by hand.

So here is my attempt to rework the services with a gulp task (once).
It follows those steps:

  • get all js files
  • look for the object assign pattern (objectAssignRegex)
  • if we have no changes we continue without changes
  • get all the services from the capture group and split them into an array
  • map through the services and do the private method trick
  • join the array with line breaks (\n)
  • wrap them in formatted object assign wrapper
  • Replace the old Object.assign contents with the generated string
  • replace all this.Service with this._Service (careful of $)
  • overwrite the contents
// make services private
const tPrivateService = () => {
    const objectAssignRegex = /Object.assign\(this, \{(.+?)\}/m;
    return gulp
        .src(packagePath + '/**/*.js', {base: './'})
        .pipe(through.obj((file, _, cb) => {
            const newFile = file.clone();
            let string = newFile.contents.toString();

            const match = string.match(objectAssignRegex);
            if (match) {
                console.log('Working on ', file.basename);

                const services = match[1]
                    .split(', ')
                    .map((service) => service.trim());

                const newServices = services
                    .map((service) => `            _${service}: ${service},`).join('\n');

                const newObjectAssign = match[0]
                    .replace(match[1], newServices)
                    .replace('{', '{\n')
                    .replace('}', '\n        }');

                string = string.replace(objectAssignRegex, newObjectAssign);

                services.forEach((service) => {
                    string = string.replace(new RegExp(`this.${service.replace(/\$/g, '\\$')}`, 'gm'), `this._${service}`);
                });

                // overwrite contents of vinyl with new buffer
                newFile.contents = Buffer.from(string);
            }
            cb(null, newFile);
        }))
        .pipe(gulp.dest('./'));
};

exports.privateService = series(tPrivateService);
Enter fullscreen mode Exit fullscreen mode

In my case, that worked for almost all files. In some cases I had the Object.assign implemented in a none standard way (with additional var declarations or line breaks).
Before you submit check all your changes.

Enjoy your privatized service injection 🎉

Coming up next

  • Privatize unused public methods in components/directives

Discussion (0)