├── .gitignore ├── .idea ├── codeStyles │ └── codeStyleConfig.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jsLibraryMappings.xml ├── misc.xml ├── modules.xml ├── node-webpackify.iml ├── typescript-compiler.xml └── vcs.xml ├── .npmignore ├── LICENSE ├── README.md ├── dist ├── __tests__ │ ├── fixtures.js │ └── fixtures.js.map ├── compiler.js ├── compiler.js.map ├── compiler.test.js ├── compiler.test.js.map ├── hook.js ├── hook.js.map ├── index.js ├── index.js.map ├── module-util.js ├── module-util.js.map ├── util-tests.js ├── util-tests.js.map ├── util-webpack.js ├── util-webpack.js.map ├── util.js └── util.js.map ├── fixtures ├── basic │ └── index.js ├── css │ ├── file.css │ ├── index.js │ ├── register.js │ └── webpack.config.js ├── postcss │ ├── file.css │ ├── file2.css │ ├── index.js │ ├── register.js │ └── webpack.config.js └── raw │ ├── file.txt │ ├── index.js │ ├── register.js │ └── webpack.config.js ├── index.js ├── package.json ├── src ├── __snapshots__ │ └── compiler.test.ts.snap ├── __tests__ │ ├── __snapshots__ │ │ └── fixtures.ts.snap │ └── fixtures.ts ├── compiler.js ├── compiler.test.ts ├── hook.js ├── index.ts ├── module-util.js ├── util-tests.ts ├── util-webpack.ts └── util.ts ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # next.js build output 63 | .next 64 | 65 | /.cache 66 | /.idea/workspace.xml 67 | /preset 68 | /assets 69 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/node-webpackify.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/typescript-compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | /src 3 | /fixtures 4 | /preset 5 | /assets 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Bazyli Brzóska 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-webpackify 2 | 3 | Redirects all your Node `require()` calls to Webpack's module compiler, 4 | making it into a JIT (just-in-time) compiler. 5 | 6 | It can serve as a replacement for `babel-register` or `ts-node`. 7 | 8 | Based on the provided `webpack` config, `node-webpackify` will use: 9 | - `webpack`'s resolvers (including resolving of aliases, resolve plugins, etc.) 10 | - `webpack`'s rules (loaders) 11 | 12 | But NOT webpack's plugins (or at least that remains untested)! 13 | The reason is that `node-webpackify` will only run a handful of hooks required to setup the resolvers and loaders. 14 | 15 | Yes, this means you can use things like `css-loader` with Node or Electron. 16 | Think: ditching `karma-webpack` in place of `electron-mocha` for much faster testing. 17 | 18 | ## Usage 19 | 20 | `node-webpackify` exposes a `register` function, which you can use by calling it with the following arguments: 21 | 22 | ```js 23 | const webpackOptions = require('./webpack.config.js') 24 | require('node-webpackify')( 25 | // webpack options object: 26 | webpackOptions, 27 | // node-webpackify options object (optional): 28 | { 29 | // (optional) function(request: string, parentPath: string): boolean 30 | // can be used to limit which requests are run through the resolvers and loaders 31 | // when left undefined, 32 | // 33 | // @param request is the string passed into: require(request) 34 | // @param parentPath is the full, absolute path to the module that the request is located in 35 | test: (request: string, parentPath: string): boolean => true, 36 | 37 | testTransform: (filename: string, loaders: Array, request: string, parentFilename: string): boolean => true, 38 | 39 | // (optional) override webpack's target (default = 'node'), useful for Electron 40 | target, 41 | } 42 | ) 43 | ``` 44 | 45 | I'd recommend creating a `register-webpack.js` file with similar contents to the file above. 46 | 47 | Then, you can simply run your code by executing: 48 | 49 | ```bash 50 | node -r ./register-webpack src/entry 51 | ``` 52 | 53 | ### Output code must be valid NodeJS code 54 | 55 | You need to ensure *none* of the output code contains ES6 `import`s (whether static or dynamic). 56 | 57 | If using Babel or TypeScript, ensure you set a CommonJS target for the module system. 58 | 59 | If you use dynamic `import()`s, you could add a babel plugin to transpile them into promisified `require()`s: 60 | - https://github.com/airbnb/babel-plugin-dynamic-import-node 61 | 62 | ## Why? 63 | 64 | - NodeJS-based testing without mocking non-JS files, 65 | e.g. running `jest` or `mocha` under Electron (which is Node + Chromium): 66 | - no build/rebuild step necessary 67 | - native watch mode 68 | - test your (post)CSS/SASS/CSSinJS *with* measuring and rendering, but *without* bundling 69 | - one config to rule them all: why should you need a different config for your testing platform, 70 | and a different one for your production? 71 | - run a Node REPL that uses your webpack configuration (resolvers, loaders, aliases), 72 | and behaves like webpack (supporting inline syntax like `require('!graphql-loader!./schema.graphql')`) 73 | - debug your `serverless` functions without `serverless-webpack`: no bundles, no sourcemap mess, no rebuilding! 74 | - things I didn't even think of 😄. 75 | - [Edit this README](https://github.com/niieani/node-webpackify/edit/master/README.md) if you have an interesting use-case! 76 | 77 | ## ES6 modules support 78 | 79 | `node-webpackify` does not add hooks to the ES6 modules system when the `--experimentalModules` flag is enabled. 80 | 81 | It shouldn't be too hard to add, as there are official APIs for hooking into that system. 82 | If you want to give it a go, send me a PR! :-) 83 | 84 | ## Performance 85 | 86 | We're transforming and loading each file on-demand, while all `require` calls are synchronous. 87 | Unfortunately this means any top-level `require`s will cascade down making the boot-up of your application slow. 88 | 89 | The way to solve this problem is to delay the `import`s as much as possible, which could be achieved using a babel plugin (explained below). 90 | It's likely not all codepaths in your application will be taken, 91 | meaning some files can be unnecessary, and others could be transformed and loaded just-in-time for their first use. 92 | 93 | This is really important in node, because `require` is synchronous, and cannot be parallelized. 94 | If you `require` any file and that contains top-level `require`s or static `import`s, 95 | all of those files, and all of *their* dependencies will have to be resolved and transformed before any other code is executed. 96 | 97 | If you're using `babel`, I recommend adding one of these plugins to the config passed into `node-webpackify` (it might not make sense in other cases): 98 | - https://github.com/zertosh/babel-plugin-transform-inline-imports-commonjs 99 | - https://github.com/princjef/babel-plugin-lazy-require 100 | 101 | They will make your `require`'s evaluate at the first moment they're used, 102 | rather than all upfront, making the start-up times much, much better. 103 | 104 | You could even try experimenting with transpiling the `node_modules` code with these, to get even better boot times! 105 | 106 | ### Open PRs with improvements! 107 | 108 | Since loaders can be slow, and `require`'s are synchronous, a lot could still be done to make `node-webpackify` faster: 109 | - long-term caching based on file timestamps (like `babel-register`) 110 | - improving logic for early bailing 111 | - resolve-only before creating the Webpack module 112 | - profile, find and eliminate bottlenecks! 113 | 114 | ## Debugging 115 | 116 | Lunch your app with a `DEBUG=node-webpackify:*` environment variable, e.g.: 117 | 118 | ```bash 119 | DEBUG=node-webpackify:* node -r ./register-webpack src/entry 120 | ``` 121 | 122 | ## Using the compiler directly 123 | 124 | It might be useful for you to just use the extracted compiler, 125 | for example to write a `jest` transform plugin out of it. 126 | 127 | See the `src/compiler.test.ts` for details on usage. 128 | -------------------------------------------------------------------------------- /dist/__tests__/fixtures.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const util_tests_1 = require("../util-tests"); 4 | describe('uses a loader', () => { 5 | jest.setTimeout(10000); 6 | it('raw-loader', async () => { 7 | const result = await util_tests_1.runFixture('raw'); 8 | expect(result.failed).toBe(false); 9 | expect(result.stdout).toMatchSnapshot(); 10 | }); 11 | it('css-loader and style-loader', async () => { 12 | const result = await util_tests_1.runFixture('css'); 13 | expect(result.failed).toBe(false); 14 | expect(result.stdout).toMatchSnapshot(); 15 | }); 16 | it('postcss-loader', async () => { 17 | const result = await util_tests_1.runFixture('postcss'); 18 | expect(result.failed).toBe(false); 19 | expect(result.stdout).toMatchSnapshot(); 20 | }); 21 | }); 22 | //# sourceMappingURL=fixtures.js.map -------------------------------------------------------------------------------- /dist/__tests__/fixtures.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../src/__tests__/fixtures.ts"],"names":[],"mappings":";;AAAA,8CAAwC;AAExC,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;IAEtB,EAAE,CAAE,YAAY,EAAE,KAAK,IAAI,EAAE;QAC3B,MAAM,MAAM,GAAG,MAAM,uBAAU,CAAC,KAAK,CAAC,CAAA;QACtC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IACzC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAE,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,MAAM,GAAG,MAAM,uBAAU,CAAC,KAAK,CAAC,CAAA;QACtC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IACzC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAE,gBAAgB,EAAE,KAAK,IAAI,EAAE;QAC/B,MAAM,MAAM,GAAG,MAAM,uBAAU,CAAC,SAAS,CAAC,CAAA;QAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IACzC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} -------------------------------------------------------------------------------- /dist/compiler.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const tslib_1 = require("tslib"); 4 | const webpack_1 = tslib_1.__importDefault(require("webpack/lib/webpack")); 5 | const fs_1 = tslib_1.__importDefault(require("fs")); 6 | const SingleEntryDependency_1 = tslib_1.__importDefault(require("webpack/lib/dependencies/SingleEntryDependency")); 7 | const SingleEntryPlugin_1 = tslib_1.__importDefault(require("webpack/lib/SingleEntryPlugin")); 8 | const util_1 = require("util"); 9 | const util_webpack_1 = require("./util-webpack"); 10 | const deasync = require('deasync'); 11 | /** @typedef {import("webpack").Configuration} Configuration */ 12 | /** 13 | * @typedef {{ 14 | * compile: function(callback : function(Error, string) : void): void, 15 | * filename: string, 16 | * request: string, 17 | * needsTransforming: boolean, 18 | * loaders: Array, 19 | * }} SimpleCompiler 20 | */ 21 | /** 22 | * @typedef {{ 23 | * compile: function(): Promise, 24 | * filename: string, 25 | * request: string, 26 | * needsTransforming: boolean, 27 | * loaders: Array, 28 | * }} SimpleCompilerAsync 29 | */ 30 | /** 31 | * @typedef {{ 32 | * compile: function(): string, 33 | * filename: string, 34 | * request: string, 35 | * needsTransforming: boolean, 36 | * loaders: Array, 37 | * }} SimpleCompilerSync 38 | */ 39 | /** 40 | * @param {Configuration} wpOptions 41 | * @param {function(Error, function(Error, SimpleCompiler=): void): void} callback 42 | * @returns {function(string, string, function(Error, SimpleCompiler=): void): void} 43 | */ 44 | function getSimpleCompiler(wpOptions, callback) { 45 | const compiler = webpack_1.default(wpOptions || {}); 46 | compiler.hooks.beforeRun.callAsync(compiler, (err) => { 47 | if (err) 48 | return callback(err); 49 | const params = compiler.newCompilationParams(); 50 | compiler.hooks.beforeCompile.callAsync(params, (err) => { 51 | if (err) 52 | return callback(err); 53 | compiler.hooks.compile.call(params); 54 | const compilation = compiler.newCompilation(params); 55 | const moduleFactory = compilation.dependencyFactories.get(SingleEntryDependency_1.default); 56 | const { options, resolverFactory } = compiler; 57 | // we never need to parse: 58 | options.module.noParse = ''; 59 | callback(undefined, (request, context, callback) => { 60 | moduleFactory.create({ 61 | context, 62 | contextInfo: { issuer: '', compiler: 'webpack-node' }, 63 | dependencies: [SingleEntryPlugin_1.default.createDependency(request, 'main')] 64 | }, (err, module) => { 65 | if (err) 66 | return callback(err); 67 | const resolver = resolverFactory.get('normal', module.resolveOptions); 68 | const compile = (callback) => { 69 | module.build(options, compilation, resolver, fs_1.default, () => { 70 | const { _source: sourceObject } = module; 71 | if (sourceObject != null) 72 | callback(null, sourceObject.source()); 73 | else 74 | callback(new Error('No source returned')); 75 | }); 76 | }; 77 | const resourceAndQuery = module.request != null 78 | ? util_webpack_1.buildFilename(module.request) 79 | : []; 80 | const filename = resourceAndQuery && resourceAndQuery.join('?'); 81 | const loaders = module.loaders || []; 82 | callback(null, { 83 | compile, 84 | module, 85 | request: module.request, 86 | loaders, 87 | resource: module.resource, 88 | filename, 89 | resourceAndQuery, 90 | needsTransforming: resourceAndQuery.length > 1 || loaders.length > 1, 91 | }); 92 | }); 93 | }); 94 | }); 95 | }); 96 | } 97 | exports.getSimpleCompiler = getSimpleCompiler; 98 | const getSimpleCompilerAsyncBase = util_1.promisify(exports.getSimpleCompiler); 99 | const getSimpleCompilerSyncBase = deasync(exports.getSimpleCompiler); 100 | /** 101 | * @typedef {function(string, string): SimpleCompilerSync} GetModuleSync 102 | */ 103 | /** 104 | * @type {function(Configuration): GetModuleSync} 105 | */ 106 | exports.getSimpleCompilerSync = (wpOptions) => { 107 | const getModule = deasync(getSimpleCompilerSyncBase(wpOptions)); 108 | /** 109 | * @param {string} request 110 | * @param {string} context 111 | * @returns {SimpleCompilerSync} 112 | */ 113 | return function getModuleSync(request, context) { 114 | const _a = getModule(request, context), { compile } = _a, props = tslib_1.__rest(_a, ["compile"]); 115 | /** @type {SimpleCompilerSync} */ 116 | return Object.assign({}, props, { compile: deasync(compile) }); 117 | }; 118 | }; 119 | /** 120 | * @typedef {function(string, string): Promise} GetModuleAsync 121 | */ 122 | /** 123 | * @type {function(Configuration): Promise} 124 | */ 125 | exports.getSimpleCompilerAsync = async (wpOptions) => { 126 | const getModule = util_1.promisify(await getSimpleCompilerAsyncBase(wpOptions)); 127 | /** 128 | * @param {string} request 129 | * @param {string} context 130 | * @returns {Promise} 131 | */ 132 | return async function getModuleAsync(request, context) { 133 | const _a = await getModule(request, context), { compile } = _a, props = tslib_1.__rest(_a, ["compile"]); 134 | /** @type {SimpleCompilerAsync} */ 135 | return Object.assign({}, props, { compile: util_1.promisify(compile) }); 136 | }; 137 | }; 138 | //# sourceMappingURL=compiler.js.map -------------------------------------------------------------------------------- /dist/compiler.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"compiler.js","sourceRoot":"","sources":["../src/compiler.js"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/compiler.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const compiler_1 = require("./compiler"); 4 | describe('simple compiler', () => { 5 | jest.setTimeout(10000); 6 | const wpOptions = {}; 7 | test('compilation async', async () => { 8 | const getModule = await compiler_1.getSimpleCompilerAsync(wpOptions); 9 | const { compile } = await getModule('../fixtures/basic', __dirname); 10 | const source = await compile(); 11 | expect(source).toMatchSnapshot(); 12 | }); 13 | test('compilation sync', () => { 14 | const getModule = compiler_1.getSimpleCompilerSync(wpOptions); 15 | const { compile } = getModule('../fixtures/basic', __dirname); 16 | const source = compile(); 17 | expect(source).toMatchSnapshot(); 18 | }); 19 | }); 20 | //# sourceMappingURL=compiler.test.js.map -------------------------------------------------------------------------------- /dist/compiler.test.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"compiler.test.js","sourceRoot":"","sources":["../src/compiler.test.ts"],"names":[],"mappings":";;AAAA,yCAAwE;AAExE,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAA;IAEtB,MAAM,SAAS,GAAG,EAAE,CAAA;IAEpB,IAAI,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,SAAS,GAAG,MAAM,iCAAsB,CAAC,SAAS,CAAC,CAAA;QACzD,MAAM,EAAC,OAAO,EAAC,GAAG,MAAM,SAAS,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAA;QACjE,MAAM,MAAM,GAAG,MAAM,OAAO,EAAE,CAAA;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC5B,MAAM,SAAS,GAAG,gCAAqB,CAAC,SAAS,CAAC,CAAA;QAClD,MAAM,EAAC,OAAO,EAAC,GAAG,SAAS,CAAC,mBAAmB,EAAE,SAAS,CAAC,CAAA;QAC3D,MAAM,MAAM,GAAG,OAAO,EAAE,CAAA;QACxB,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} -------------------------------------------------------------------------------- /dist/hook.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const tslib_1 = require("tslib"); 4 | // noinspection NpmUsedModulesInstalled 5 | const module_1 = tslib_1.__importDefault(require("module")); 6 | const path_1 = require("path"); 7 | const compiler_1 = require("./compiler"); 8 | const module_util_1 = require("./module-util"); 9 | const util_1 = require("./util"); 10 | const debug_1 = tslib_1.__importDefault(require("debug")); 11 | const { _load: load } = module_1.default; 12 | const logLoad = debug_1.default('webpack-node:load'); 13 | const logResolve = debug_1.default('webpack-node:resolve'); 14 | const logError = debug_1.default('webpack-node:error'); 15 | const logCompilationStart = debug_1.default('webpack-node:compile:start'); 16 | const logCompilationEnd = debug_1.default('webpack-node:compile:end'); 17 | const anyLogEnabled = logLoad.enabled || logResolve.enabled || logError.enabled || logCompilationStart.enabled || logCompilationEnd.enabled; 18 | function register(wpOptions = {}, options = {}) { 19 | module_1.default._load = makeLoad(wpOptions, options); 20 | } 21 | exports.register = register; 22 | function makeLoad(wpOptions = {}, { test, testTransform, blacklistBuiltin = true, target = 'node', } = {}) { 23 | const getModule = compiler_1.getSimpleCompilerSync(Object.assign({}, wpOptions, { target })); 24 | return function _load(request, parentModule, isMain) { 25 | const { filename: parentFilename = '' } = parentModule || {}; 26 | const shouldBail = isMain 27 | || parentFilename === '' 28 | || (blacklistBuiltin && module_1.default.builtinModules.some((builtIn) => request.startsWith(builtIn))) 29 | || (test && !test(request, parentFilename)); 30 | if (!shouldBail) { 31 | try { 32 | const context = path_1.dirname(parentFilename); 33 | const prettyContext = anyLogEnabled ? util_1.getPrettyPath(context) : ''; 34 | logLoad('loading %o', { request, context: prettyContext }); 35 | const { compile, filename, needsTransforming, loaders } = getModule(request, context); 36 | const prettyFilename = anyLogEnabled ? util_1.getPrettyPath(filename) : ''; 37 | logResolve('resolved %o', { filename: prettyFilename, needsTransforming }); 38 | const wantsTransforming = testTransform 39 | && testTransform(filename, loaders, request, parentFilename, needsTransforming); 40 | if (wantsTransforming || needsTransforming) { 41 | const cachedModule = module_util_1.getCachedModule(filename, parentModule); 42 | if (cachedModule) 43 | return cachedModule.exports; 44 | logCompilationStart('compiling %s', prettyFilename); 45 | let compiled = ''; 46 | try { 47 | compiled = compile(); 48 | } 49 | catch (error) { 50 | logError('error transforming %o', { filename: prettyFilename, request }); 51 | console.error(error); 52 | return {}; 53 | } 54 | if (logCompilationEnd.enabled) { 55 | logCompilationEnd('compiled %O', { 56 | filename: prettyFilename, 57 | loaders: loaders.map(({ loader }) => util_1.getPrettyPath(loader)), 58 | }); 59 | } 60 | try { 61 | const newModule = module_util_1.makeModule(filename, compiled, parentModule); 62 | return newModule.exports; 63 | } 64 | catch (error) { 65 | logError('error executing %o', { filename: prettyFilename, request }); 66 | console.error(error); 67 | throw error; 68 | } 69 | } 70 | else { 71 | // we bailed, but we might already have resolved the filename - let's use it: 72 | request = filename != null ? filename : request; 73 | } 74 | } 75 | catch (err) { 76 | logError('error resolving %o', { request, parent: util_1.getPrettyPath(parentFilename), err }); 77 | } 78 | } 79 | if (anyLogEnabled) 80 | logLoad('passing to native loader %s', util_1.getPrettyPath(request)); 81 | return load(request, parentModule, isMain); 82 | }; 83 | } 84 | exports.makeLoad = makeLoad; 85 | //# sourceMappingURL=hook.js.map -------------------------------------------------------------------------------- /dist/hook.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.js"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var hook_1 = require("./hook"); 4 | exports.register = hook_1.register; 5 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,+BAA+B;AAAvB,0BAAA,QAAQ,CAAA"} -------------------------------------------------------------------------------- /dist/module-util.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const tslib_1 = require("tslib"); 4 | // https://github.com/nodejs/node/blob/254058109f469f64b8ca23bb65a206abab380604/lib/internal/modules/cjs/loader.js#L87 5 | const module_1 = tslib_1.__importDefault(require("module")); 6 | const path_1 = require("path"); 7 | function updateChildren(parent, child, scan) { 8 | const children = parent && parent.children; 9 | if (children && !(scan && children.includes(child))) 10 | children.push(child); 11 | } 12 | exports.updateChildren = updateChildren; 13 | exports.stripBom = (string /* : string */) => string.charCodeAt(0) === 0xFEFF ? string.slice(1) : string; 14 | // from https://github.com/nodejs/node/blob/254058109f469f64b8ca23bb65a206abab380604/lib/internal/modules/cjs/loader.js#L525 15 | function tryModuleLoad(newModule, filename, content) { 16 | let threw = true; 17 | try { 18 | // from https://github.com/nodejs/node/blob/254058109f469f64b8ca23bb65a206abab380604/lib/internal/modules/cjs/loader.js#L580 19 | newModule.filename = filename; 20 | newModule.paths = module_1.default._nodeModulePaths(path_1.dirname(filename)); 21 | newModule._compile(exports.stripBom(content), filename); 22 | newModule.loaded = true; 23 | threw = false; 24 | } 25 | finally { 26 | if (threw) { 27 | delete module_1.default._cache[filename]; 28 | } 29 | } 30 | } 31 | exports.tryModuleLoad = tryModuleLoad; 32 | exports.getCachedModule = (filename, parentModule) => { 33 | const cachedModule = module_1.default._cache[filename]; 34 | if (cachedModule) { 35 | updateChildren(parentModule, cachedModule, true); 36 | return cachedModule; 37 | } 38 | return undefined; 39 | }; 40 | function makeModule(filename, fileContents, parentModule) { 41 | const newModule = new module_1.default(filename, parentModule); 42 | module_1.default._cache[filename] = newModule; 43 | tryModuleLoad(newModule, filename, fileContents); 44 | return newModule; 45 | } 46 | exports.makeModule = makeModule; 47 | //# sourceMappingURL=module-util.js.map -------------------------------------------------------------------------------- /dist/module-util.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"module-util.js","sourceRoot":"","sources":["../src/module-util.js"],"names":[],"mappings":";;;AAAA,sHAAsH;AACtH,4DAA2B;AAC3B,+BAA4B;AAE5B,SAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI;IAChD,MAAM,QAAQ,GAAG,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAA;IAC1C,IAAI,QAAQ,IAAI,CAAC,CAAC,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACjD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AACxB,CAAC;AAJD,wCAIC;AAEY,QAAA,QAAQ,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAChD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAA;AAE5D,4HAA4H;AAC5H,SAAgB,aAAa,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO;IACxD,IAAI,KAAK,GAAG,IAAI,CAAA;IAChB,IAAI;QACF,4HAA4H;QAC5H,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAA;QAC7B,SAAS,CAAC,KAAK,GAAG,gBAAM,CAAC,gBAAgB,CAAC,cAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC5D,SAAS,CAAC,QAAQ,CAAC,gBAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAA;QAC/C,SAAS,CAAC,MAAM,GAAG,IAAI,CAAA;QACvB,KAAK,GAAG,KAAK,CAAA;KACd;YAAS;QACR,IAAI,KAAK,EAAE;YACT,OAAO,gBAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;SAC/B;KACF;AACH,CAAC;AAdD,sCAcC;AAEY,QAAA,eAAe,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE;IACxD,MAAM,YAAY,GAAG,gBAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC5C,IAAI,YAAY,EAAE;QAChB,cAAc,CAAC,YAAY,EAAE,YAAY,EAAE,IAAI,CAAC,CAAA;QAChD,OAAO,YAAY,CAAA;KACpB;IACD,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAED,SAAgB,UAAU,CAAC,QAAQ,EAAE,YAAY,EAAE,YAAY;IAC7D,MAAM,SAAS,GAAG,IAAI,gBAAM,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;IACpD,gBAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAA;IACnC,aAAa,CAAC,SAAS,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAA;IAChD,OAAO,SAAS,CAAA;AAClB,CAAC;AALD,gCAKC"} -------------------------------------------------------------------------------- /dist/util-tests.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const tslib_1 = require("tslib"); 4 | const path_1 = require("path"); 5 | const execa_1 = tslib_1.__importDefault(require("execa")); 6 | function runFixture(name) { 7 | const fixturePath = path_1.resolve(__dirname, '..', 'fixtures', name); 8 | return execa_1.default('node', ['-r', path_1.join(fixturePath, 'register'), fixturePath]); 9 | } 10 | exports.runFixture = runFixture; 11 | //# sourceMappingURL=util-tests.js.map -------------------------------------------------------------------------------- /dist/util-tests.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"util-tests.js","sourceRoot":"","sources":["../src/util-tests.ts"],"names":[],"mappings":";;;AAAA,+BAAkC;AAClC,0DAAyB;AAEzB,SAAgB,UAAU,CAAC,IAAY;IACrC,MAAM,WAAW,GAAG,cAAO,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,CAAA;IAC9D,OAAO,eAAK,CACV,MAAM,EACN,CAAC,IAAI,EAAE,WAAI,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,WAAW,CAAC,CACnD,CAAA;AACH,CAAC;AAND,gCAMC"} -------------------------------------------------------------------------------- /dist/util-webpack.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const tslib_1 = require("tslib"); 4 | const crypto_1 = tslib_1.__importDefault(require("crypto")); 5 | /** 6 | * @param {string} request 7 | * @returns {[string, string]} 8 | */ 9 | function buildFilename(request) { 10 | const loaders = request.split('!'); 11 | const [resource, ...paramsParts] = loaders.pop().split('?'); 12 | const hashFrom = `${loaders.join('!')}${paramsParts.join('?')}`; 13 | return hashFrom.length > 0 14 | ? [resource, crypto_1.default.createHash('md4').update(hashFrom).digest('hex')] 15 | : [resource]; 16 | } 17 | exports.buildFilename = buildFilename; 18 | //# sourceMappingURL=util-webpack.js.map -------------------------------------------------------------------------------- /dist/util-webpack.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"util-webpack.js","sourceRoot":"","sources":["../src/util-webpack.ts"],"names":[],"mappings":";;;AAAA,4DAA2B;AAE3B;;;GAGG;AACH,SAAgB,aAAa,CAAC,OAAe;IAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAClC,MAAM,CAAC,QAAQ,EAAE,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,GAAG,EAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC5D,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/D,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC;QACxB,CAAC,CAAC,CAAC,QAAQ,EAAE,gBAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;AAChB,CAAC;AAPD,sCAOC"} -------------------------------------------------------------------------------- /dist/util.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const deasync = require("deasync"); 4 | const util_1 = require("util"); 5 | const path_1 = require("path"); 6 | function deasyncAsyncFn(asyncFn) { 7 | return deasync(util_1.callbackify(asyncFn)); 8 | } 9 | exports.deasyncAsyncFn = deasyncAsyncFn; 10 | exports.getPrettyPath = (filename) => filename 11 | .split(`${process.cwd()}${path_1.sep}`) 12 | .pop() 13 | .split(`node_modules${path_1.sep}`) 14 | .pop(); 15 | //# sourceMappingURL=util.js.map -------------------------------------------------------------------------------- /dist/util.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;AAAA,mCAAmC;AACnC,+BAAgC;AAChC,+BAAwB;AAYxB,SAAgB,cAAc,CAC5B,OAA6C;IAE7C,OAAO,OAAO,CAAC,kBAAW,CAAC,OAAO,CAAC,CAAC,CAAA;AACtC,CAAC;AAJD,wCAIC;AAEY,QAAA,aAAa,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,QAAQ;KACxD,KAAK,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,GAAG,UAAG,EAAE,CAAC;KAC/B,GAAG,EAAG;KACN,KAAK,CAAC,eAAe,UAAG,EAAE,CAAC;KAC3B,GAAG,EAAG,CAAA"} -------------------------------------------------------------------------------- /fixtures/basic/index.js: -------------------------------------------------------------------------------- 1 | console.log('basic') 2 | -------------------------------------------------------------------------------- /fixtures/css/file.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: black; 3 | } 4 | -------------------------------------------------------------------------------- /fixtures/css/index.js: -------------------------------------------------------------------------------- 1 | require('jsdom-global')() 2 | require('./file.css') 3 | console.log(document.documentElement.innerHTML) 4 | -------------------------------------------------------------------------------- /fixtures/css/register.js: -------------------------------------------------------------------------------- 1 | require('../../dist/hook').register(require('./webpack.config')) 2 | -------------------------------------------------------------------------------- /fixtures/css/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | module: { 3 | rules: [ 4 | { 5 | test: /\.css$/, 6 | use: [ 7 | { loader: 'style-loader' }, 8 | { loader: 'css-loader' }, 9 | ] 10 | } 11 | ], 12 | }, 13 | } -------------------------------------------------------------------------------- /fixtures/postcss/file.css: -------------------------------------------------------------------------------- 1 | @import "./file2.css"; 2 | 3 | body { 4 | color: black; 5 | } 6 | -------------------------------------------------------------------------------- /fixtures/postcss/file2.css: -------------------------------------------------------------------------------- 1 | .hello { 2 | color: blanchedalmond; 3 | animation: linear; 4 | } -------------------------------------------------------------------------------- /fixtures/postcss/index.js: -------------------------------------------------------------------------------- 1 | require('jsdom-global')() 2 | require('./file.css') 3 | console.log(document.documentElement.innerHTML) 4 | -------------------------------------------------------------------------------- /fixtures/postcss/register.js: -------------------------------------------------------------------------------- 1 | require('../../dist/hook').register(require('./webpack.config')) 2 | -------------------------------------------------------------------------------- /fixtures/postcss/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | module: { 3 | rules: [ 4 | { 5 | test: /\.css$/, 6 | use: [ 7 | { loader: 'style-loader' }, 8 | { loader: 'css-loader', options: { modules: true, importLoaders: 1 } }, 9 | { 10 | loader: 'postcss-loader', 11 | options: { 12 | ident: 'postcss', 13 | plugins: (loader) => [ 14 | require('postcss-import')({ root: loader.resourcePath }), 15 | require('autoprefixer')(), 16 | ] 17 | }, 18 | }, 19 | ] 20 | } 21 | ], 22 | }, 23 | } -------------------------------------------------------------------------------- /fixtures/raw/file.txt: -------------------------------------------------------------------------------- 1 | I'm a text file -------------------------------------------------------------------------------- /fixtures/raw/index.js: -------------------------------------------------------------------------------- 1 | console.log( 2 | require('./file.txt') 3 | ) 4 | -------------------------------------------------------------------------------- /fixtures/raw/register.js: -------------------------------------------------------------------------------- 1 | require('../../dist/hook').register(require('./webpack.config')) 2 | -------------------------------------------------------------------------------- /fixtures/raw/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | module: { 3 | rules: [ 4 | {test: /\.txt$/, loader: 'raw-loader'} 5 | ], 6 | } 7 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist/hook').register 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-webpackify", 3 | "version": "2.1.2", 4 | "description": "Utility for redirecting require() requests in Node to Webpack's module compiler", 5 | "keywords": [ 6 | "node", 7 | "babel-register", 8 | "register", 9 | "JIT", 10 | "compiler", 11 | "webpack" 12 | ], 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/niieani/node-webpackify.git" 16 | }, 17 | "homepage": "https://github.com/niieani/node-webpackify#readme", 18 | "author": "Bazyli Brzóska ", 19 | "collaborators": [ 20 | "Bazyli Brzóska " 21 | ], 22 | "license": "MIT", 23 | "main": "index.js", 24 | "scripts": { 25 | "test": "jest", 26 | "build": "tsc -p ." 27 | }, 28 | "dependencies": { 29 | "deasync": "^0.1.13", 30 | "debug": "^3.1.0", 31 | "tslib": "^1.9.0", 32 | "webpack": "^4.0.0" 33 | }, 34 | "devDependencies": { 35 | "@types/deasync": "0.1.0", 36 | "@types/debug": "0.0.30", 37 | "@types/execa": "0.9.0", 38 | "@types/jest": "23.3.1", 39 | "@types/node": "^10.9.4", 40 | "@types/webpack": "4.4.11", 41 | "autoprefixer": "9.1.3", 42 | "css-loader": "1.0.0", 43 | "execa": "1.0.0", 44 | "jest": "23.5.0", 45 | "jsdom": "12.0.0", 46 | "jsdom-global": "3.0.2", 47 | "postcss-import": "12.0.0", 48 | "postcss-loader": "3.0.0", 49 | "raw-loader": "0.5.1", 50 | "style-loader": "0.23.0", 51 | "ts-jest": "23.1.4", 52 | "typescript": "3.0.3", 53 | "webpack-command": "0.4.1" 54 | }, 55 | "jest": { 56 | "transform": { 57 | "^.+\\/src\\/.+\\.[jt]sx?$": "ts-jest" 58 | }, 59 | "testRegex": "\\/src\\/.*(__tests__/.*|\\.test)\\.ts$", 60 | "moduleFileExtensions": [ 61 | "ts", 62 | "tsx", 63 | "js", 64 | "jsx", 65 | "json", 66 | "node" 67 | ], 68 | "globals": { 69 | "ts-jest": { 70 | "skipBabel": true 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/__snapshots__/compiler.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`simple compiler compilation async 1`] = ` 4 | "console.log('basic') 5 | " 6 | `; 7 | 8 | exports[`simple compiler compilation sync 1`] = ` 9 | "console.log('basic') 10 | " 11 | `; 12 | -------------------------------------------------------------------------------- /src/__tests__/__snapshots__/fixtures.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`uses a loader css-loader and style-loader 1`] = ` 4 | "" 8 | `; 9 | 10 | exports[`uses a loader postcss-loader 1`] = ` 11 | "" 21 | `; 22 | 23 | exports[`uses a loader raw-loader 1`] = `"I'm a text file"`; 24 | -------------------------------------------------------------------------------- /src/__tests__/fixtures.ts: -------------------------------------------------------------------------------- 1 | import {runFixture} from '../util-tests' 2 | 3 | describe('uses a loader', () => { 4 | jest.setTimeout(10000) 5 | 6 | it ('raw-loader', async () => { 7 | const result = await runFixture('raw') 8 | expect(result.failed).toBe(false) 9 | expect(result.stdout).toMatchSnapshot() 10 | }) 11 | 12 | it ('css-loader and style-loader', async () => { 13 | const result = await runFixture('css') 14 | expect(result.failed).toBe(false) 15 | expect(result.stdout).toMatchSnapshot() 16 | }) 17 | 18 | it ('postcss-loader', async () => { 19 | const result = await runFixture('postcss') 20 | expect(result.failed).toBe(false) 21 | expect(result.stdout).toMatchSnapshot() 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /src/compiler.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack/lib/webpack' 2 | import fs from 'fs' 3 | import SingleEntryDependency from 'webpack/lib/dependencies/SingleEntryDependency' 4 | import SingleEntryPlugin from 'webpack/lib/SingleEntryPlugin' 5 | import {promisify} from 'util' 6 | import {buildFilename} from './util-webpack' 7 | const deasync = require('deasync') 8 | 9 | /** @typedef {import("webpack").Configuration} Configuration */ 10 | 11 | /** 12 | * @typedef {{ 13 | * compile: function(callback : function(Error, string) : void): void, 14 | * filename: string, 15 | * request: string, 16 | * needsTransforming: boolean, 17 | * loaders: Array, 18 | * }} SimpleCompiler 19 | */ 20 | 21 | /** 22 | * @typedef {{ 23 | * compile: function(): Promise, 24 | * filename: string, 25 | * request: string, 26 | * needsTransforming: boolean, 27 | * loaders: Array, 28 | * }} SimpleCompilerAsync 29 | */ 30 | 31 | /** 32 | * @typedef {{ 33 | * compile: function(): string, 34 | * filename: string, 35 | * request: string, 36 | * needsTransforming: boolean, 37 | * loaders: Array, 38 | * }} SimpleCompilerSync 39 | */ 40 | 41 | /** 42 | * @param {Configuration} wpOptions 43 | * @param {function(Error, function(Error, SimpleCompiler=): void): void} callback 44 | * @returns {function(string, string, function(Error, SimpleCompiler=): void): void} 45 | */ 46 | export function getSimpleCompiler(wpOptions, callback) { 47 | const compiler = webpack(wpOptions || {}) 48 | compiler.hooks.beforeRun.callAsync(compiler, (err) => { 49 | if (err) return callback(err) 50 | 51 | const params = compiler.newCompilationParams() 52 | compiler.hooks.beforeCompile.callAsync(params, (err) => { 53 | if (err) return callback(err) 54 | 55 | compiler.hooks.compile.call(params) 56 | const compilation = compiler.newCompilation(params) 57 | const moduleFactory = compilation.dependencyFactories.get(SingleEntryDependency) 58 | const {options, resolverFactory} = compiler 59 | 60 | // we never need to parse: 61 | options.module.noParse = '' 62 | 63 | callback(undefined, (request, context, callback) => { 64 | moduleFactory.create({ 65 | context, 66 | contextInfo: {issuer: '', compiler: 'webpack-node'}, 67 | dependencies: [SingleEntryPlugin.createDependency(request, 'main')] 68 | }, (err, module) => { 69 | if (err) return callback(err) 70 | 71 | const resolver = resolverFactory.get('normal', module.resolveOptions) 72 | const compile = (callback) => { 73 | module.build(options, compilation, resolver, fs, () => { 74 | const {_source: sourceObject} = module 75 | if (sourceObject != null) callback(null, sourceObject.source()) 76 | else callback(new Error('No source returned')) 77 | }) 78 | } 79 | 80 | const resourceAndQuery = module.request != null 81 | ? buildFilename(module.request) 82 | : [] 83 | 84 | const filename = resourceAndQuery && resourceAndQuery.join('?') 85 | const loaders = module.loaders || [] 86 | 87 | callback(null, { 88 | compile, 89 | module, 90 | request: module.request, 91 | loaders, 92 | resource: module.resource, 93 | filename, 94 | resourceAndQuery, 95 | needsTransforming: resourceAndQuery.length > 1 || loaders.length > 1, 96 | }) 97 | }) 98 | }) 99 | }) 100 | }) 101 | } 102 | 103 | const getSimpleCompilerAsyncBase = promisify(getSimpleCompiler) 104 | const getSimpleCompilerSyncBase = deasync(getSimpleCompiler) 105 | 106 | /** 107 | * @typedef {function(string, string): SimpleCompilerSync} GetModuleSync 108 | */ 109 | 110 | /** 111 | * @type {function(Configuration): GetModuleSync} 112 | */ 113 | export const getSimpleCompilerSync = (wpOptions) => { 114 | const getModule = deasync(getSimpleCompilerSyncBase(wpOptions)) 115 | /** 116 | * @param {string} request 117 | * @param {string} context 118 | * @returns {SimpleCompilerSync} 119 | */ 120 | return function getModuleSync(request, context) { 121 | const {compile, ...props} = getModule(request, context) 122 | /** @type {SimpleCompilerSync} */ 123 | return {...props, compile: deasync(compile)} 124 | } 125 | } 126 | 127 | /** 128 | * @typedef {function(string, string): Promise} GetModuleAsync 129 | */ 130 | 131 | /** 132 | * @type {function(Configuration): Promise} 133 | */ 134 | export const getSimpleCompilerAsync = async (wpOptions) => { 135 | const getModule = promisify(await getSimpleCompilerAsyncBase(wpOptions)) 136 | /** 137 | * @param {string} request 138 | * @param {string} context 139 | * @returns {Promise} 140 | */ 141 | return async function getModuleAsync(request, context) { 142 | const {compile, ...props} = await getModule(request, context) 143 | /** @type {SimpleCompilerAsync} */ 144 | return {...props, compile: promisify(compile)} 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/compiler.test.ts: -------------------------------------------------------------------------------- 1 | import {getSimpleCompilerAsync, getSimpleCompilerSync} from './compiler' 2 | 3 | describe('simple compiler', () => { 4 | jest.setTimeout(10000) 5 | 6 | const wpOptions = {} 7 | 8 | test('compilation async', async () => { 9 | const getModule = await getSimpleCompilerAsync(wpOptions) 10 | const {compile} = await getModule('../fixtures/basic', __dirname) 11 | const source = await compile() 12 | expect(source).toMatchSnapshot() 13 | }) 14 | 15 | test('compilation sync', () => { 16 | const getModule = getSimpleCompilerSync(wpOptions) 17 | const {compile} = getModule('../fixtures/basic', __dirname) 18 | const source = compile() 19 | expect(source).toMatchSnapshot() 20 | }) 21 | }) 22 | -------------------------------------------------------------------------------- /src/hook.js: -------------------------------------------------------------------------------- 1 | // noinspection NpmUsedModulesInstalled 2 | import Module from 'module' 3 | import {dirname, extname} from 'path' 4 | import {getSimpleCompilerSync} from './compiler' 5 | import {makeModule, getCachedModule} from './module-util' 6 | import {getPrettyPath} from './util' 7 | import makeDebug from 'debug' 8 | const {_load: load} = Module 9 | 10 | const logLoad = makeDebug('webpack-node:load') 11 | const logResolve = makeDebug('webpack-node:resolve') 12 | const logError = makeDebug('webpack-node:error') 13 | const logCompilationStart = makeDebug('webpack-node:compile:start') 14 | const logCompilationEnd = makeDebug('webpack-node:compile:end') 15 | 16 | const anyLogEnabled = logLoad.enabled || logResolve.enabled || logError.enabled || logCompilationStart.enabled || logCompilationEnd.enabled 17 | 18 | export function register( 19 | wpOptions = {}, 20 | options = {}, 21 | ) { 22 | Module._load = makeLoad(wpOptions, options) 23 | } 24 | 25 | export function makeLoad( 26 | wpOptions = {}, 27 | { 28 | test, 29 | testTransform, 30 | blacklistBuiltin = true, 31 | target = 'node', 32 | } = {} 33 | ) { 34 | const getModule = getSimpleCompilerSync({...wpOptions, target}) 35 | 36 | return function _load(request, parentModule, isMain) { 37 | const {filename: parentFilename = ''} = parentModule || {} 38 | 39 | const shouldBail = isMain 40 | || parentFilename === '' 41 | || (blacklistBuiltin && Module.builtinModules.some((builtIn) => request.startsWith(builtIn))) 42 | || (test && !test(request, parentFilename)) 43 | 44 | if (!shouldBail) { 45 | try { 46 | const context = dirname(parentFilename) 47 | const prettyContext = anyLogEnabled ? getPrettyPath(context) : '' 48 | logLoad('loading %o', {request, context: prettyContext}) 49 | 50 | const {compile, filename, needsTransforming, loaders} = getModule(request, context) 51 | const prettyFilename = anyLogEnabled ? getPrettyPath(filename) : '' 52 | logResolve('resolved %o', {filename: prettyFilename, needsTransforming}) 53 | 54 | const wantsTransforming = testTransform 55 | && testTransform(filename, loaders, request, parentFilename, needsTransforming) 56 | 57 | if (wantsTransforming || needsTransforming) { 58 | const cachedModule = getCachedModule(filename, parentModule) 59 | if (cachedModule) return cachedModule.exports 60 | 61 | logCompilationStart('compiling %s', prettyFilename) 62 | 63 | let compiled = '' 64 | try { 65 | compiled = compile() 66 | } catch (error) { 67 | logError('error transforming %o', {filename: prettyFilename, request}) 68 | console.error(error) 69 | return {} 70 | } 71 | if (logCompilationEnd.enabled) { 72 | logCompilationEnd('compiled %O', { 73 | filename: prettyFilename, 74 | loaders: loaders.map(({loader}) => getPrettyPath(loader)), 75 | }) 76 | } 77 | try { 78 | const newModule = makeModule(filename, compiled, parentModule) 79 | return newModule.exports 80 | } catch (error) { 81 | logError('error executing %o', {filename: prettyFilename, request}) 82 | console.error(error) 83 | throw error 84 | } 85 | } else { 86 | // we bailed, but we might already have resolved the filename - let's use it: 87 | request = filename != null ? filename : request 88 | } 89 | } catch (err) { 90 | logError('error resolving %o', {request, parent: getPrettyPath(parentFilename), err}) 91 | } 92 | } 93 | if (anyLogEnabled) logLoad('passing to native loader %s', getPrettyPath(request)) 94 | return load(request, parentModule, isMain) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export {register} from './hook' 2 | -------------------------------------------------------------------------------- /src/module-util.js: -------------------------------------------------------------------------------- 1 | // https://github.com/nodejs/node/blob/254058109f469f64b8ca23bb65a206abab380604/lib/internal/modules/cjs/loader.js#L87 2 | import Module from "module" 3 | import {dirname} from "path" 4 | 5 | export function updateChildren(parent, child, scan) { 6 | const children = parent && parent.children 7 | if (children && !(scan && children.includes(child))) 8 | children.push(child) 9 | } 10 | 11 | export const stripBom = (string /* : string */) => 12 | string.charCodeAt(0) === 0xFEFF ? string.slice(1) : string 13 | 14 | // from https://github.com/nodejs/node/blob/254058109f469f64b8ca23bb65a206abab380604/lib/internal/modules/cjs/loader.js#L525 15 | export function tryModuleLoad(newModule, filename, content) { 16 | let threw = true 17 | try { 18 | // from https://github.com/nodejs/node/blob/254058109f469f64b8ca23bb65a206abab380604/lib/internal/modules/cjs/loader.js#L580 19 | newModule.filename = filename 20 | newModule.paths = Module._nodeModulePaths(dirname(filename)) 21 | newModule._compile(stripBom(content), filename) 22 | newModule.loaded = true 23 | threw = false 24 | } finally { 25 | if (threw) { 26 | delete Module._cache[filename] 27 | } 28 | } 29 | } 30 | 31 | export const getCachedModule = (filename, parentModule) => { 32 | const cachedModule = Module._cache[filename] 33 | if (cachedModule) { 34 | updateChildren(parentModule, cachedModule, true) 35 | return cachedModule 36 | } 37 | return undefined 38 | } 39 | 40 | export function makeModule(filename, fileContents, parentModule) { 41 | const newModule = new Module(filename, parentModule) 42 | Module._cache[filename] = newModule 43 | tryModuleLoad(newModule, filename, fileContents) 44 | return newModule 45 | } 46 | -------------------------------------------------------------------------------- /src/util-tests.ts: -------------------------------------------------------------------------------- 1 | import {resolve, join} from 'path' 2 | import execa from 'execa' 3 | 4 | export function runFixture(name: string) { 5 | const fixturePath = resolve(__dirname, '..', 'fixtures', name) 6 | return execa( 7 | 'node', 8 | ['-r', join(fixturePath, 'register'), fixturePath] 9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /src/util-webpack.ts: -------------------------------------------------------------------------------- 1 | import crypto from 'crypto' 2 | 3 | /** 4 | * @param {string} request 5 | * @returns {[string, string]} 6 | */ 7 | export function buildFilename(request: string) { 8 | const loaders = request.split('!') 9 | const [resource, ...paramsParts] = loaders.pop()!.split('?') 10 | const hashFrom = `${loaders.join('!')}${paramsParts.join('?')}` 11 | return hashFrom.length > 0 12 | ? [resource, crypto.createHash('md4').update(hashFrom).digest('hex')] 13 | : [resource] 14 | } -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | import deasync = require('deasync') 2 | import {callbackify} from 'util' 3 | import {sep} from 'path' 4 | 5 | type DeasyncAsyncFn = () => any>( 6 | asyncFn: (arg : T) => Promise 7 | ) => (arg: T) => U) 8 | 9 | export function deasyncAsyncFn( 10 | asyncFn: (arg : T) => Promise 11 | ): (arg: T) => U 12 | export function deasyncAsyncFn( 13 | asyncFn: (arg : T, arg2: T2) => Promise 14 | ): (arg: T, arg2: T2) => U 15 | export function deasyncAsyncFn( 16 | asyncFn: (...args : Array) => Promise 17 | ): (...args: Array) => U { 18 | return deasync(callbackify(asyncFn)) 19 | } 20 | 21 | export const getPrettyPath = (filename: string) => filename 22 | .split(`${process.cwd()}${sep}`) 23 | .pop()! 24 | .split(`node_modules${sep}`) 25 | .pop()! 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "es2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ 5 | "module": "commonjs", /* Specify module code generation: 'none', commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | "lib": ["esnext"], /* Specify library files to be included in the compilation: */ 7 | "allowJs": true, /* Allow javascript files to be compiled. */ 8 | "checkJs": false, /* Report errors in .js files. */ 9 | // "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 10 | // "jsxFactory": "console.log", 11 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 12 | "sourceMap": true, /* Generates corresponding '.map' file. */ 13 | // "outFile": "./", /* Concatenate and emit output to single file. */ 14 | "outDir": "dist", /* Redirect output structure to the directory. */ 15 | "rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 16 | // "removeComments": true, /* Do not emit comments to output. */ 17 | // "noEmit": true, /* Do not emit outputs. */ 18 | "importHelpers": true, /* Import emit helpers from 'tslib'. */ 19 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 20 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 21 | 22 | /* Strict Type-Checking Options */ 23 | "strict": true, /* Enable all strict type-checking options. */ 24 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 25 | // "strictNullChecks": true, /* Enable strict null checks. */ 26 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 27 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 28 | 29 | /* Additional Checks */ 30 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 31 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 32 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 33 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 34 | 35 | /* Module Resolution Options */ 36 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 37 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 38 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 39 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 40 | // "typeRoots": [], /* List of folders to include type definitions from. */ 41 | // "types": [], /* Type declaration files to be included in compilation. */ 42 | "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 43 | "esModuleInterop": true, 44 | "watch": true 45 | /* Source Map Options */ 46 | // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 47 | // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ 48 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 49 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 50 | 51 | /* Experimental Options */ 52 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 53 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 54 | // "skipLibCheck": true 55 | }, 56 | "include": ["src"] 57 | } 58 | --------------------------------------------------------------------------------