Skip to content

Remove Svelte 2 HMR #153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 1 addition & 98 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,104 +145,7 @@ This should create an additional `styles.css.map` file.

### Hot Reload

Hot reloading is turned off by default, you can turn it on using the `hotReload` option as shown below:

```javascript
...
module: {
rules: [
...
{
test: /\.(html|svelte)$/,
exclude: /node_modules/,
use: {
loader: 'svelte-loader',
options: {
hotReload: true
}
}
}
...
]
}
...
```

#### Hot reload rules and caveats:

- `_rerender` and `_register` are reserved method names, please don't use them in `methods:{...}`
- Turning `dev` mode on (`dev:true`) is **not** necessary.
- Modifying the HTML (template) part of your component will replace and re-render the changes in place. Current local state of the component will also be preserved (this can be turned off per component see [Stop preserving state](#stop-preserving-state)).
- When modifying the `<script>` part of your component, instances will be replaced and re-rendered in place too.
However if your component has lifecycle methods that produce global side-effects, you might need to reload the whole page.
- If you are using `svelte/store`, a full reload is required if you modify `store` properties


Components will **not** be hot reloaded in the following situations:
1. `process.env.NODE_ENV === 'production'`
2. Webpack is minifying code
3. Webpack's `target` is `node` (i.e SSR components)
4. `generate` option has a value of `ssr`

#### Stop preserving state

Sometimes it might be necessary for some components to avoid state preservation on hot reload.

This can be configured on a per-component basis by adding a property `noPreserveState = true` to the component's constructor using the `setup()` method. For example:
```js
export default {
setup(comp){
comp.noPreserveState = true;
},
data(){return {...}},
oncreate(){...}
}
```

Or, on a global basis by adding `{noPreserveState: true}` to `hotOptions`. For example:
```js
{
test: /\.(html|svelte)$/,
exclude: /node_modules/,
use: [
{
loader: 'svelte-loader',
options: {
hotReload: true,
hotOptions: {
noPreserveState: true
}
}
}
]
}
```

**Please Note:** If you are using `svelte/store`, `noPreserveState` has no effect on `store` properties. Neither locally, nor globally.

#### External Dependencies

If you rely on any external dependencies (files required in a preprocessor for example) you might want to watch these files for changes and re-run svelte compile.

Webpack allows [loader dependencies](https://webpack.js.org/contribute/writing-a-loader/#loader-dependencies) to trigger a recompile. svelte-loader exposes this API via `options.externalDependencies`.
For example:

```js
...
const variables = path.resolve('./variables.js');
...
{
test: /\.(html|svelte)$/,
use: [
{
loader: 'svelte-loader',
options: {
externalDependencies: [variables]
}
}
]
}
```
See [rixo/svelte-hmr](https://github.com/rixo/svelte-hmr#webpack) for info on how to setup hot module reloading (HMR).

## License

Expand Down
40 changes: 0 additions & 40 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,18 @@
const { relative } = require('path');
const { getOptions } = require('loader-utils');

const hotApi = require.resolve('./lib/hot-api.js');

const { compile, preprocess } = require('svelte/compiler');

const pluginOptions = {
externalDependencies: true,
hotReload: true,
hotOptions: true,
preprocess: true,
emitCss: true,

// legacy
onwarn: true,
shared: true,
style: true,
script: true,
markup: true
};

function makeHot(id, code, hotOptions) {
const options = JSON.stringify(hotOptions);
const replacement = `
if (module.hot) {
const { configure, register, reload } = require('${posixify(hotApi)}');

module.hot.accept();

if (!module.hot.data) {
// initial load
configure(${options});
$2 = register(${id}, $2);
} else {
// hot update
$2 = reload(${id}, $2);
}
}

export default $2;
`;

return code.replace(/(export default ([^;]*));/, () => replacement);
}

function posixify(file) {
return file.replace(/[/\\]/g, '/');
}
Expand Down Expand Up @@ -94,9 +63,6 @@ module.exports = function(source, map) {
return;
}

const isServer = this.target === 'node' || (options.generate && options.generate == 'ssr');
const isProduction = this.minimize || process.env.NODE_ENV === 'production';

const compileOptions = {
filename: this.resourcePath,
format: options.format || 'esm'
Expand Down Expand Up @@ -128,12 +94,6 @@ module.exports = function(source, map) {
: handleWarning
);

if (options.hotReload && !isProduction && !isServer) {
const hotOptions = Object.assign({}, options.hotOptions);
const id = JSON.stringify(relative(process.cwd(), compileOptions.filename));
js.code = makeHot(id, js.code, hotOptions);
}

if (options.emitCss && css.code) {
const resource = posixify(compileOptions.filename);
const cssPath = `${resource}.${index++}.css`;
Expand Down
51 changes: 0 additions & 51 deletions lib/hot-api.js

This file was deleted.

5 changes: 0 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@
"scripts": {
"all": "npm run lint && npm run test",
"test": "mocha --harmony --full-trace --check-leaks",
"lint": "eslint index.js lib/*.js test/**/*.js"
"lint": "eslint index.js test/**/*.js"
},
"keywords": [
"svelte",
"sveltejs",
"webpack-loader"
],
"dependencies": {
"loader-utils": "^1.1.0",
"svelte-dev-helper": "^1.1.9"
"loader-utils": "^1.1.0"
},
"devDependencies": {
"chai": "^4.1.2",
Expand All @@ -35,7 +34,6 @@
"url": "[email protected]:sveltejs/svelte-loader.git"
},
"files": [
"lib",
"index.js"
]
}
77 changes: 0 additions & 77 deletions test/loader.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,83 +298,6 @@ describe('loader', () => {
)(done);
});
});

describe('hotReload', () => {
it(
'should configure hotReload=false (default)',
testLoader(
'test/fixtures/good.html',
function(err, code, map) {
expect(err).not.to.exist;

expect(code).not.to.contain('module.hot.accept();');
},
{}
)
);

it(
'should configure hotReload=true',
testLoader(
'test/fixtures/good.html',
function(err, code, map) {
expect(err).not.to.exist;

expect(code).to.contain('module.hot.accept();');
expect(code).not.to.contain('configure({"noPreserveState":true});');
},
{ hotReload: true }
)
);

it(
'should configure hotReload=true & hotOptions',
testLoader(
'test/fixtures/good.html',
function(err, code, map) {
expect(err).not.to.exist;

expect(code).to.contain('module.hot.accept();');
expect(code).to.contain('configure({"noPreserveState":true});');
},
{
hotReload: true,
hotOptions: {
noPreserveState: true
}
}
)
);

it(
'should ignore hotReload when generate=ssr',
testLoader(
'test/fixtures/good.html',
function(err, code, map) {
expect(err).not.to.exist;

expect(code).not.to.contain('module.hot.accept();');
},
{
hotReload: true,
generate: 'ssr'
}
)
);

it(
'should require resolved hot-api.js',
testLoader(
'test/fixtures/good.html',
function(err, code, map) {
expect(err).not.to.exist;

expect(code).to.contain(require.resolve('../lib/hot-api.js').replace(/[/\\]/g, '/'));
},
{ hotReload: true }
)
);
});
});
});

Expand Down