diff --git a/.gitignore b/.gitignore index 2f9c7302..4ab4a5ea 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ jasmine-config/reporter.js.map hooks .DS_Store + +!projectHelpers.spec.js diff --git a/.npmignore b/.npmignore index a6d37dc4..1c2c46d5 100644 --- a/.npmignore +++ b/.npmignore @@ -4,3 +4,12 @@ demo *.ts !*.d.ts +*.spec.* +.vscode/ +.github/ +jasmine-config/ +CONTRIBUTING.md +CODE_OF_CONDUCT.md +PULL_REQUEST_TESTS.md + +*.tgz diff --git a/CHANGELOG.md b/CHANGELOG.md index 03c56161..87f98095 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,38 @@ + +## [0.18.3](https://github.com/NativeScript/nativescript-dev-webpack/compare/0.18.2...0.18.3) (2018-12-10) + + +### Bug Fixes + +* project's package.json indentation is not persisted ([#727](https://github.com/NativeScript/nativescript-dev-webpack/issues/727)) ([a45a45c](https://github.com/NativeScript/nativescript-dev-webpack/commit/a45a45c)) + + + + +## [0.18.2](https://github.com/NativeScript/nativescript-dev-webpack/compare/0.18.1...0.18.2) (2018-12-06) + + +### Bug Fixes + +* avoid getting `js` template in a `ts` project ([#717](https://github.com/NativeScript/nativescript-dev-webpack/issues/717)) ([c121c24](https://github.com/NativeScript/nativescript-dev-webpack/commit/c121c24)) + + +### Features + +* **HMR:** expose context ([#724](https://github.com/NativeScript/nativescript-dev-webpack/issues/724)) ([c14110c](https://github.com/NativeScript/nativescript-dev-webpack/commit/c14110c)) + + + + +## [0.18.1](https://github.com/NativeScript/nativescript-dev-webpack/compare/0.18.0...0.18.1) (2018-12-03) + + +### Bug Fixes + +* avoid getting `js` template in a `ts` project ([#717](https://github.com/NativeScript/nativescript-dev-webpack/issues/717)) ([c121c24](https://github.com/NativeScript/nativescript-dev-webpack/commit/c121c24)) + + + # [0.18.0](https://github.com/NativeScript/nativescript-dev-webpack/compare/0.17.0...0.18.0) (2018-11-13) diff --git a/LICENSE b/LICENSE index 59dc28ed..9d63a0a6 100755 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright (c) 2015-2018 Telerik EAD + Copyright (c) 2015-2018 Progress Software Corporation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/bundle-config-loader.js b/bundle-config-loader.js index 92b73398..c3d6f763 100644 --- a/bundle-config-loader.js +++ b/bundle-config-loader.js @@ -19,12 +19,12 @@ module.exports = function (source) { require("nativescript-dev-webpack/hot")(__webpack_require__.h(), (fileName) => applicationFiles.getFile(fileName)); }; - global.__hmrRefresh = function(type) { + global.__hmrRefresh = function({ type, module }) { global.__hmrNeedReload = true; setTimeout(() => { if(global.__hmrNeedReload) { global.__hmrNeedReload = false; - global.__hmrLivesyncBackup(); + global.__hmrLivesyncBackup({ type, module }); } }); } @@ -45,9 +45,9 @@ module.exports = function (source) { if (loadCss) { source = ` require("${ - angular ? - 'nativescript-dev-webpack/load-application-css-angular' : - 'nativescript-dev-webpack/load-application-css-regular' + angular ? + 'nativescript-dev-webpack/load-application-css-angular' : + 'nativescript-dev-webpack/load-application-css-regular' }")(); ${source} `; diff --git a/demo/AngularApp/package.json b/demo/AngularApp/package.json index 43b2daf6..a5bfb550 100644 --- a/demo/AngularApp/package.json +++ b/demo/AngularApp/package.json @@ -13,45 +13,45 @@ } }, "dependencies": { - "@angular/common": "~6.1.0", - "@angular/compiler": "~6.1.0", - "@angular/core": "~6.1.0", - "@angular/forms": "~6.1.0", - "@angular/http": "~6.1.0", - "@angular/platform-browser": "~6.1.0", - "@angular/platform-browser-dynamic": "~6.1.0", - "@angular/router": "~6.1.0", + "@angular/common": "~7.1.0", + "@angular/compiler": "~7.1.0", + "@angular/core": "~7.1.0", + "@angular/forms": "~7.1.0", + "@angular/http": "~7.1.0", + "@angular/platform-browser": "~7.1.0", + "@angular/platform-browser-dynamic": "~7.1.0", + "@angular/router": "~7.1.0", "nativescript-angular": "next", "nativescript-theme-core": "~1.0.2", "reflect-metadata": "~0.1.8", - "rxjs": "^6.0.0", + "rxjs": "~6.3.3", "tns-core-modules": "next", - "zone.js": "^0.8.26" + "zone.js": "~0.8.26" }, "devDependencies": { - "@angular/compiler-cli": "~6.1.0", - "@ngtools/webpack": "~6.2.0", - "@types/chai": "^4.0.2", - "@types/mocha": "^2.2.41", - "@types/node": "^7.0.5", + "@angular/compiler-cli": "~7.1.0", + "@ngtools/webpack": "~7.1.2", + "@types/chai": "~4.1.7", + "@types/mocha": "~5.2.5", + "@types/node": "~10.12.12", "babel-traverse": "6.26.0", "babel-types": "6.26.0", "babylon": "6.18.0", "chai": "~4.1.1", "chai-as-promised": "~7.1.1", "lazy": "1.0.11", - "mocha": "~3.5.0", - "mocha-junit-reporter": "^1.13.0", - "mocha-multi": "^0.11.0", + "mocha": "~5.2.0", + "mocha-junit-reporter": "~1.18.0", + "mocha-multi": "~1.0.1", "nativescript-dev-appium": "next", "nativescript-dev-sass": "next", "nativescript-dev-typescript": "next", "nativescript-dev-webpack": "next", - "typescript": "~2.7.2" + "typescript": "~3.1.1" }, "scripts": { "setup": "npm pack ../../ && npm i -D nativescript-dev-webpack*.tgz", "e2e": "tsc -p e2e && mocha --opts ../config/mocha.opts --recursive e2e --appiumCapsLocation ../config/appium.capabilities.json", "compile-tests": "tsc -p e2e --watch" } -} +} \ No newline at end of file diff --git a/demo/JavaScriptApp/package.json b/demo/JavaScriptApp/package.json index c9ccd161..ee3eb6e2 100644 --- a/demo/JavaScriptApp/package.json +++ b/demo/JavaScriptApp/package.json @@ -17,16 +17,16 @@ "tns-core-modules": "next" }, "devDependencies": { - "@types/chai": "^4.0.2", - "@types/mocha": "^2.2.41", - "@types/node": "^7.0.5", + "@types/chai": "~4.1.7", + "@types/mocha": "~5.2.5", + "@types/node": "~10.12.12", "babel-traverse": "6.26.0", "babel-types": "6.26.0", "babylon": "6.18.0", "lazy": "1.0.11", - "mocha": "~3.5.0", - "mocha-junit-reporter": "^1.13.0", - "mocha-multi": "^0.11.0", + "mocha": "~5.2.0", + "mocha-junit-reporter":"~1.18.0", + "mocha-multi":"~1.0.1", "nativescript-dev-appium": "next", "nativescript-dev-sass": "next", "nativescript-dev-webpack": "next", @@ -36,4 +36,4 @@ "setup": "npm pack ../../ && npm i -D nativescript-dev-webpack*.tgz", "e2e": "mocha --opts ../config/mocha.opts --recursive e2e --appiumCapsLocation ../config/appium.capabilities.json" } -} +} \ No newline at end of file diff --git a/demo/TypeScriptApp/package.json b/demo/TypeScriptApp/package.json index 524e952a..babf8489 100644 --- a/demo/TypeScriptApp/package.json +++ b/demo/TypeScriptApp/package.json @@ -17,21 +17,21 @@ "tns-core-modules": "next" }, "devDependencies": { - "@types/chai": "^4.0.2", - "@types/mocha": "^2.2.41", - "@types/node": "^7.0.5", + "@types/chai": "~4.1.7", + "@types/mocha": "~5.2.5", + "@types/node": "~10.12.12", "babel-traverse": "6.26.0", "babel-types": "6.26.0", "babylon": "6.18.0", "lazy": "1.0.11", - "mocha": "~3.5.0", - "mocha-junit-reporter": "^1.13.0", - "mocha-multi": "^0.11.0", + "mocha": "~5.2.0", + "mocha-junit-reporter": "~1.18.0", + "mocha-multi": "~1.0.1", "nativescript-dev-appium": "next", "nativescript-dev-sass": "next", "nativescript-dev-typescript": "next", "nativescript-dev-webpack": "next", - "typescript": "~2.7.2" + "typescript": "~3.2.2" }, "scripts": { "setup": "npm pack ../../ && npm i -D nativescript-dev-webpack*.tgz", diff --git a/dependencyManager.js b/dependencyManager.js index 18417ded..6fe1549a 100644 --- a/dependencyManager.js +++ b/dependencyManager.js @@ -86,11 +86,11 @@ function getRequiredDeps(packageJson) { } const deps = { - "@angular/compiler-cli": "~7.0.0", + "@angular/compiler-cli": "~7.1.0", }; if (!dependsOn(packageJson, "@angular-devkit/build-angular")) { - deps["@ngtools/webpack"] = "~7.0.0"; + deps["@ngtools/webpack"] = "~7.1.0"; } return deps; diff --git a/hot-loader-helper.js b/hot-loader-helper.js index 1314d277..49dd51d5 100644 --- a/hot-loader-helper.js +++ b/hot-loader-helper.js @@ -1,9 +1,9 @@ -module.exports.reload = function(type) { return ` +module.exports.reload = function ({ type, module }) { + return ` if (module.hot) { module.hot.accept(); module.hot.dispose(() => { - global.__hmrRefresh('${type}'); + global.__hmrRefresh({ type: '${type}', module: '${module}' }); }) } `}; - diff --git a/jasmine-config/jasmine.json b/jasmine-config/jasmine.json index 31a4a781..84db3eb2 100644 --- a/jasmine-config/jasmine.json +++ b/jasmine-config/jasmine.json @@ -1,7 +1,8 @@ { "spec_dir": ".", "spec_files": [ - "./!(node_modules)/**/*.spec.js" + "./!(node_modules)/**/*.spec.js", + "./*.spec.js" ], "helpers": [ "jasmine-config/**/*.js" diff --git a/markup-hot-loader.js b/markup-hot-loader.js index 6d330447..601cb16f 100644 --- a/markup-hot-loader.js +++ b/markup-hot-loader.js @@ -1,5 +1,7 @@ const { reload } = require("./hot-loader-helper"); module.exports = function (source) { - return `${source};${reload('markup')}`; + const typeMarkup = "markup"; + const modulePath = this.resourcePath.replace(this.context, "."); + return `${source};${reload({ type: typeMarkup, module: modulePath })}`; }; diff --git a/package.json b/package.json index b15438ed..3c04976b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nativescript-dev-webpack", - "version": "0.18.0", + "version": "0.18.3", "main": "index", "description": "", "homepage": "http://www.telerik.com", @@ -60,7 +60,7 @@ "scripts": { "postinstall": "node postinstall.js", "postpack": "rm -rf node_modules", - "prepare": "tsc", + "prepare": "tsc && npm run jasmine", "test": "npm run prepare && npm run jasmine", "jasmine": "jasmine --config=jasmine-config/jasmine.json", "version": "rm package-lock.json && conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md" @@ -83,26 +83,26 @@ "semver": "5.4.1", "shelljs": "0.6.0", "tapable": "1.0.0", - "webpack": "~4.24.0", + "webpack": "~4.27.0", "webpack-cli": "~3.1.1", "webpack-bundle-analyzer": "~3.0.2", "webpack-sources": "~1.3.0", - "clean-webpack-plugin": "~0.1.19", + "clean-webpack-plugin": "~1.0.0", "copy-webpack-plugin": "~4.6.0", "raw-loader": "~0.5.1", "css-loader": "~1.0.0", "nativescript-worker-loader": "~0.9.0", "extract-text-webpack-plugin": "~3.0.2", "uglifyjs-webpack-plugin": "~1.2.5", - "@angular-devkit/core": "~7.0.0", + "@angular-devkit/core": "~7.1.0", "resolve-url-loader": "~3.0.0", "awesome-typescript-loader": "~5.2.1", "sass-loader": "~7.1.0" }, "devDependencies": { - "@ngtools/webpack": "~7.0.0", - "@types/jasmine": "^2.8.8", - "@types/node": "^8.0.0", + "@ngtools/webpack": "~7.1.0", + "@types/jasmine": "^3.3.1", + "@types/node": "^10.12.12", "conventional-changelog-cli": "^1.3.22", "jasmine": "^3.2.0", "jasmine-spec-reporter": "^4.2.1", diff --git a/projectHelpers.js b/projectHelpers.js index d4266015..0f61b76c 100644 --- a/projectHelpers.js +++ b/projectHelpers.js @@ -1,5 +1,5 @@ const { resolve } = require("path"); -const { readFileSync, writeFileSync } = require("fs"); +const fs = require("fs"); const hook = require("nativescript-hook")(__dirname); @@ -13,11 +13,13 @@ const isTypeScript = ({ projectDir, packageJson } = {}) => { return ( packageJson.dependencies && - packageJson.dependencies.hasOwnProperty("typescript") + (packageJson.dependencies.hasOwnProperty("nativescript-dev-typescript") || + packageJson.dependencies.hasOwnProperty("typescript")) ) || ( - packageJson.devDependencies && - packageJson.devDependencies.hasOwnProperty("typescript") - ) || isAngular({ packageJson }); + packageJson.devDependencies && + (packageJson.devDependencies.hasOwnProperty("nativescript-dev-typescript") || + packageJson.devDependencies.hasOwnProperty("typescript")) + ) || isAngular({ packageJson }); }; const isAngular = ({ projectDir, packageJson } = {}) => { @@ -36,13 +38,26 @@ const isVue = ({ projectDir, packageJson } = {}) => { const getPackageJson = projectDir => { const packageJsonPath = getPackageJsonPath(projectDir); - return JSON.parse(readFileSync(packageJsonPath, "utf8")); + return JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); }; const writePackageJson = (content, projectDir) => { const packageJsonPath = getPackageJsonPath(projectDir); - writeFileSync(packageJsonPath, JSON.stringify(content, null, 2)) + const currentJsonContent = fs.readFileSync(packageJsonPath); + const indentation = getIndentationCharacter(currentJsonContent); + const stringifiedContent = JSON.stringify(content, null, indentation); + const currentPackageJsonContent = JSON.parse(currentJsonContent); + + if (JSON.stringify(currentPackageJsonContent, null, indentation) !== stringifiedContent) { + fs.writeFileSync(packageJsonPath, stringifiedContent) + } } + +const getIndentationCharacter = (jsonContent) => { + const matches = jsonContent && jsonContent.toString().match(/{\r*\n*(\W*)"/m); + return matches && matches[1]; +} + const getProjectDir = hook.findProjectDir; const getPackageJsonPath = projectDir => resolve(projectDir, "package.json"); @@ -94,5 +109,6 @@ module.exports = { isVue, isTypeScript, writePackageJson, - convertSlashesInPath + convertSlashesInPath, + getIndentationCharacter }; \ No newline at end of file diff --git a/projectHelpers.spec.js b/projectHelpers.spec.js new file mode 100644 index 00000000..c8a83b88 --- /dev/null +++ b/projectHelpers.spec.js @@ -0,0 +1,110 @@ +const { getIndentationCharacter, writePackageJson } = require("./projectHelpers"); +const fs = require("fs"); + +describe('projectHelpers', () => { + const originalReadFileSync = fs.readFileSync; + const originalWriteFileSync = fs.writeFileSync; + const tab = "\t"; + const multipleSpaces = " "; + const twoSpaces = " "; + + afterEach(() => { + fs.readFileSync = originalReadFileSync; + fs.writeFileSync = originalWriteFileSync; + }); + + describe('getIndentationCharacter', () => { + [ + { + testName: 'returns two spaces when file starts with two spaces', + input: `{${twoSpaces}"abc": "1"${twoSpaces}}`, + expectedResult: twoSpaces + }, + { + testName: 'returns two spaces when file starts with two spaces and binary content is passed', + input: Buffer.from(`{${twoSpaces}"abc": "1"${twoSpaces}}`), + expectedResult: twoSpaces + }, + { + testName: 'returns empty string when file starts without any indentation', + input: `{"abc": "1"}`, + expectedResult: '' + }, + { + testName: 'returns tab when file starts with tab', + input: `{${tab}"abc": "1"${tab}}`, + expectedResult: tab + }, + { + testName: 'returns two spaces when file starts with two spaces and new line before them', + input: `{\n${twoSpaces}"abc": "1"\n}`, + expectedResult: twoSpaces + }, + { + testName: 'returns tab when file starts with tab and new line before them', + input: `{\n${tab}"abc": "1"\n}`, + expectedResult: tab + }, + { + testName: 'returns multiple spaces when file starts with multiple spaces and new line before them', + input: `{\n${multipleSpaces}"abc": "1"\n}`, + expectedResult: multipleSpaces + } + ].forEach(({ testName, input, expectedResult }) => { + it(testName, () => { + expect(getIndentationCharacter(input)).toEqual(expectedResult); + }); + }); + }); + + describe('writePackageJson', () => { + const mockFileSystemApi = () => { + const data = { + isWriteFileSyncCalled: false + }; + + fs.readFileSync = (p) => { + return JSON.stringify({ a: 1 }); + }; + + fs.writeFileSync = (p, c) => { + data.isWriteFileSyncCalled = true; + }; + + return data; + }; + + it('does not write package.json when content has not changed', () => { + const data = mockFileSystemApi(); + writePackageJson({ a: 1 }, "projDir"); + expect(data.isWriteFileSyncCalled).toBe(false); + }); + + it('writes content, when the new one is different from the current one', () => { + const data = mockFileSystemApi(); + writePackageJson({ b: 2 }, "projDir"); + expect(data.isWriteFileSyncCalled).toBe(true); + }); + + it('keeps indentation of the package.json when rewriting it', () => { + let currentIndentSymbol = tab; + fs.readFileSync = (p) => { + return JSON.stringify({ a: 1 }, null, currentIndentSymbol); + }; + + let writtenContent = null; + fs.writeFileSync = (p, c) => { + writtenContent = c; + }; + + // Ensure tab indentation is persisted + writePackageJson({ b: 2 }, "projDir"); + expect(writtenContent).toBe(`{\n${tab}"b": 2\n}`); + + // Ensure spaces indentation is persisted + currentIndentSymbol = multipleSpaces; + writePackageJson({ b: 2 }, "projDir"); + expect(writtenContent).toBe(`{\n${multipleSpaces}"b": 2\n}`); + }); + }); +}); diff --git a/script-hot-loader.js b/script-hot-loader.js index c8ba3e30..7f59aaaa 100644 --- a/script-hot-loader.js +++ b/script-hot-loader.js @@ -1,5 +1,7 @@ const { reload } = require("./hot-loader-helper"); module.exports = function (source) { - return `${source};${reload('script')}`; + const typeScript = "script"; + const modulePath = this.resourcePath.replace(this.context, "."); + return `${source};${reload({ type: typeScript, module: modulePath })}`; }; diff --git a/style-hot-loader.js b/style-hot-loader.js index 23e6ad72..90fd5ce8 100644 --- a/style-hot-loader.js +++ b/style-hot-loader.js @@ -1,5 +1,7 @@ const { reload } = require("./hot-loader-helper"); module.exports = function (source) { - return `${source};${reload('style')}`; + const typeStyle = "style"; + const modulePath = this.resourcePath.replace(this.context, "."); + return `${source};${reload({ type: typeStyle, module: modulePath })}`; };