diff --git a/README.md b/README.md index a4b7cf0..82ee8e5 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ This plugin can be used as a drop-in replacement for `svelte-loader`. It aims to Configure inside your `webpack.config.js`: ```javascript +// required for emitting css through webpack-virtual-modules plugin +const SveltePlugin = require('svelte-loader-hot').plugin; + module.exports = { ... module: { @@ -82,12 +85,20 @@ module.exports = { } } } + }, + { + // required to prevent errors from Svelte on Webpack 5+ + test: /svelte\/.*\.mjs$/, + resolve: { + fullySpecified: false + } } ... ] }, plugins: [ new webpack.HotModuleReplacementPlugin(), + new SveltePlugin(), ... ] } diff --git a/index.js b/index.js index bfbdf58..90b0d11 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ const { basename, extname, relative } = require('path'); const { getOptions } = require('loader-utils'); -const VirtualModules = require('./lib/virtual'); +const VirtualModules = require('webpack-virtual-modules'); const posixify = require('./lib/posixify'); const { @@ -68,13 +68,9 @@ function deprecatePreprocessOptions(options) { options.preprocess = options.preprocess || preprocessOptions; } -const virtualModuleInstances = new Map(); - -module.exports = function(source, map) { - if (this._compiler && !virtualModuleInstances.has(this._compiler)) { - virtualModuleInstances.set(this._compiler, new VirtualModules(this._compiler)); - } +let virtualModuleInstances = new WeakMap(); +function loader(source, map) { const virtualModules = virtualModuleInstances.get(this._compiler); this.cacheable(); @@ -142,9 +138,26 @@ module.exports = function(source, map) { css.code += '\n/*# sourceMappingURL=' + css.map.toUrl() + '*/'; js.code = js.code + `\nimport '${posixify(cssFilepath)}';\n`; - if (virtualModules) { - virtualModules.writeModule(cssFilepath, css.code); + if (!virtualModules) { + throw new Error( + ` + + To be able to use emitCss: true, add + + const SveltePlugin = require('svelte-loader').plugin; + + to the top of your webpack.config.js and + SveltePlugin to the plugins array like this + + plugins: [ + ... + new SveltePlugin() + ] + `.split('\n').map(s => s.slice(5)).join('\n') + ); } + + virtualModules.writeModule(cssFilepath, css.code); } callback(null, js.code, js.map); @@ -153,4 +166,15 @@ module.exports = function(source, map) { // context when logging to console callback(new Error(`${err.name}: ${err.toString()}`)); }); -}; +} + +class SveltePlugin extends VirtualModules { + apply(compiler) { + virtualModuleInstances.set(compiler, this); + super.apply(compiler); + } +} + +loader.plugin = SveltePlugin; + +module.exports = loader; diff --git a/lib/virtual-stats.js b/lib/virtual-stats.js deleted file mode 100644 index 4e1b1de..0000000 --- a/lib/virtual-stats.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Used to cache a stats object for the virtual file. - * Extracted from the `mock-fs` package. - * - * @author Tim Schaub http://tschaub.net/ - * @link https://github.com/tschaub/mock-fs/blob/master/lib/binding.js - * @link https://github.com/tschaub/mock-fs/blob/master/license.md - */ - -/* eslint-disable no-restricted-syntax, no-prototype-builtins, no-continue */ -/* eslint-disable no-bitwise, no-underscore-dangle */ - -'use strict'; - -var constants = require('constants'); - -/** - * Create a new stats object. - * @param {Object} config Stats properties. - * @constructor - */ -function VirtualStats(config) { - for (var key in config) { - if (!config.hasOwnProperty(key)) { - continue; - } - this[key] = config[key]; - } -} - -/** - * Check if mode indicates property. - * @param {number} property Property to check. - * @return {boolean} Property matches mode. - */ -VirtualStats.prototype._checkModeProperty = function(property) { - return (this.mode & constants.S_IFMT) === property; -}; - -/** - * @return {Boolean} Is a directory. - */ -VirtualStats.prototype.isDirectory = function() { - return this._checkModeProperty(constants.S_IFDIR); -}; - -/** - * @return {Boolean} Is a regular file. - */ -VirtualStats.prototype.isFile = function() { - return this._checkModeProperty(constants.S_IFREG); -}; - -/** - * @return {Boolean} Is a block device. - */ -VirtualStats.prototype.isBlockDevice = function() { - return this._checkModeProperty(constants.S_IFBLK); -}; - -/** - * @return {Boolean} Is a character device. - */ -VirtualStats.prototype.isCharacterDevice = function() { - return this._checkModeProperty(constants.S_IFCHR); -}; - -/** - * @return {Boolean} Is a symbolic link. - */ -VirtualStats.prototype.isSymbolicLink = function() { - return this._checkModeProperty(constants.S_IFLNK); -}; - -/** - * @return {Boolean} Is a named pipe. - */ -VirtualStats.prototype.isFIFO = function() { - return this._checkModeProperty(constants.S_IFIFO); -}; - -/** - * @return {Boolean} Is a socket. - */ -VirtualStats.prototype.isSocket = function() { - return this._checkModeProperty(constants.S_IFSOCK); -}; - -module.exports = VirtualStats; diff --git a/lib/virtual.js b/lib/virtual.js deleted file mode 100644 index 7dec0ee..0000000 --- a/lib/virtual.js +++ /dev/null @@ -1,81 +0,0 @@ -var VirtualStats = require('./virtual-stats'); - -var inode = 45000000; - -// Adapted from https://github.com/sysgears/webpack-virtual-modules -// MIT Licensed https://github.com/sysgears/webpack-virtual-modules/blob/master/LICENSE - -function VirtualModulesPlugin(compiler) { - this.compiler = compiler; - - if (!compiler.inputFileSystem._writeVirtualFile) { - var originalPurge = compiler.inputFileSystem.purge; - - compiler.inputFileSystem.purge = function() { - if (originalPurge) { - originalPurge.call(this, arguments); - } - if (this._virtualFiles) { - Object.keys(this._virtualFiles).forEach( - function(file) { - var data = this._virtualFiles[file]; - setData(this._statStorage, file, [null, data.stats]); - setData(this._readFileStorage, file, [null, data.contents]); - }.bind(this) - ); - } - }; - - compiler.inputFileSystem._writeVirtualFile = function(file, stats, contents) { - this._virtualFiles = this._virtualFiles || {}; - this._virtualFiles[file] = { stats: stats, contents: contents }; - setData(this._statStorage, file, [null, stats]); - setData(this._readFileStorage, file, [null, contents]); - }; - } - - const watchRunHook = (watcher, callback) => { - this._watcher = watcher.compiler || watcher; - callback(); - }; - - if (compiler.hooks) { - compiler.hooks.watchRun.tapAsync('VirtualModulesPlugin', watchRunHook); - } else { - compiler.plugin('watch-run', watchRunHook); - } -} - -VirtualModulesPlugin.prototype.writeModule = function(filePath, contents) { - var len = contents ? contents.length : 0; - var time = Date.now(); - - var stats = new VirtualStats({ - dev: 8675309, - nlink: 0, - uid: 1000, - gid: 1000, - rdev: 0, - blksize: 4096, - ino: inode++, - mode: 33188, - size: len, - blocks: Math.floor(len / 4096), - atime: time, - mtime: time, - ctime: time, - birthtime: time - }); - - this.compiler.inputFileSystem._writeVirtualFile(filePath, stats, contents); -}; - -function setData(storage, key, value) { - if (storage.data instanceof Map) { - storage.data.set(key, value); - } else { - storage.data[key] = value; - } -} - -module.exports = VirtualModulesPlugin; diff --git a/package.json b/package.json index 14dd944..a5816d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte-loader-hot", - "version": "0.3.1", + "version": "1.0.0", "author": "Nico Rehwaldt ", "maintainers": [ { @@ -27,7 +27,8 @@ "dependencies": { "loader-utils": "^1.1.0", "svelte-dev-helper": "^1.1.9", - "svelte-hmr": "^0.10.3" + "svelte-hmr": "^0.10.3", + "webpack-virtual-modules": "^0.4.1" }, "devDependencies": { "chai": "^4.1.2", diff --git a/test/loader.spec.js b/test/loader.spec.js index 79b628a..5319782 100644 --- a/test/loader.spec.js +++ b/test/loader.spec.js @@ -208,19 +208,6 @@ describe('loader', () => { {} ) ); - - it( - 'should configure emitCss=true', - testLoader( - 'test/fixtures/css.html', - function(err, code, map) { - expect(err).not.to.exist; - - expect(code).to.match(/import '.+\.css';/); - }, - { emitCss: true } - ) - ); }); describe('preprocess', () => {