From e14f81944c188186affe9f07f69a1b107f3fb38f Mon Sep 17 00:00:00 2001 From: Dan Bucholtz Date: Wed, 5 Jul 2017 23:18:48 -0500 Subject: [PATCH] feature(webpack): add scope hoisting to webpack, update sass to read scss files from disk --- config/webpack.config.js | 3 +++ src/optimization.ts | 19 +++++++++++++++---- src/preprocess.spec.ts | 21 +++++++++++++++++++-- src/preprocess.ts | 19 ++++++++++++++++--- src/rollup.ts | 13 +------------ src/webpack.ts | 17 +---------------- 6 files changed, 55 insertions(+), 37 deletions(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index f58f0d2b..30a58cc5 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -2,6 +2,8 @@ var path = require('path'); var webpack = require('webpack'); var ionicWebpackFactory = require(process.env.IONIC_WEBPACK_FACTORY); +var ModuleConcatPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin'); + module.exports = { entry: process.env.IONIC_APP_ENTRY_POINT, output: { @@ -36,6 +38,7 @@ module.exports = { plugins: [ ionicWebpackFactory.getIonicEnvironmentPlugin(), + new ModuleConcatPlugin() ], // Some libraries import Node modules but don't use them in the browser. diff --git a/src/optimization.ts b/src/optimization.ts index d9a4344b..f016db80 100644 --- a/src/optimization.ts +++ b/src/optimization.ts @@ -1,4 +1,4 @@ -import { basename, extname } from 'path'; +import { basename, dirname, extname, join } from 'path'; import * as MagicString from 'magic-string'; @@ -76,6 +76,7 @@ export function doOptimizations(context: BuildContext, dependencyMap: Map>, purgedModules: Map>) { + const includedModuleSet = new Set(); + originalDependencyMap.forEach((set: Set, modulePath: string) => { + if (!purgedModules.has(modulePath)) { + includedModuleSet.add(modulePath); + } + }); + context.moduleFiles = Array.from(includedModuleSet); +} + function optimizationEnabled() { const purgeDecorators = getBooleanPropertyValue(Constants.ENV_PURGE_DECORATORS); const manualTreeshaking = getBooleanPropertyValue(Constants.ENV_MANUAL_TREESHAKING); @@ -193,8 +204,8 @@ export function getConfig(context: BuildContext, configFile: string): WebpackCon const taskInfo: TaskInfo = { fullArg: '--optimization', - shortArg: '-dt', - envVar: 'IONIC_DEPENDENCY_TREE', - packageConfig: 'ionic_dependency_tree', + shortArg: '-op', + envVar: 'IONIC_OPTIMIZATION', + packageConfig: 'ionic_optimization', defaultConfigFile: 'optimization.config' }; diff --git a/src/preprocess.spec.ts b/src/preprocess.spec.ts index 7dd549c1..aa9983f9 100644 --- a/src/preprocess.spec.ts +++ b/src/preprocess.spec.ts @@ -1,8 +1,9 @@ +import { join } from 'path'; import * as preprocess from './preprocess'; import * as deeplink from './deep-linking'; import * as helpers from './util/helpers'; import * as optimization from './optimization'; - +import * as globUtil from './util/glob-util'; describe('Preprocess Task', () => { describe('preprocess', () => { @@ -12,10 +13,16 @@ describe('Preprocess Task', () => { optimizeJs: false }; + const mockDirName = join('some', 'fake', 'dir'); + const mockGlobResults = []; + mockGlobResults.push({ absolutePath: mockDirName}); + mockGlobResults.push({ absolutePath: mockDirName + '2'}); spyOn(deeplink, deeplink.deepLinking.name).and.returnValue(Promise.resolve()); spyOn(optimization, optimization.optimization.name).and.returnValue(Promise.resolve()); spyOn(helpers, helpers.getBooleanPropertyValue.name).and.returnValue(false); spyOn(preprocess, preprocess.writeFilesToDisk.name).and.returnValue(null); + spyOn(helpers, helpers.getStringPropertyValue.name).and.returnValue(mockDirName); + spyOn(globUtil, globUtil.globAll.name).and.returnValue(Promise.resolve(mockGlobResults)); // act return preprocess.preprocess(context).then(() => { @@ -27,20 +34,30 @@ describe('Preprocess Task', () => { it('should call optimization or write files to disk', () => { // arrange - const context = { + const context: any = { optimizeJs: true }; + const mockDirName = join('some', 'fake', 'dir'); + const mockGlobResults = []; + mockGlobResults.push({ absolutePath: mockDirName}); + mockGlobResults.push({ absolutePath: mockDirName + '2'}); spyOn(deeplink, deeplink.deepLinking.name).and.returnValue(Promise.resolve()); spyOn(optimization, optimization.optimization.name).and.returnValue(Promise.resolve()); spyOn(helpers, helpers.getBooleanPropertyValue.name).and.returnValue(false); spyOn(preprocess, preprocess.writeFilesToDisk.name).and.returnValue(null); + spyOn(helpers, helpers.getStringPropertyValue.name).and.returnValue(mockDirName); + spyOn(globUtil, globUtil.globAll.name).and.returnValue(Promise.resolve(mockGlobResults)); // act return preprocess.preprocess(context).then(() => { // assert expect(optimization.optimization).toHaveBeenCalled(); expect(preprocess.writeFilesToDisk).not.toHaveBeenCalledWith(); + expect(context.moduleFiles).toBeTruthy(); + expect(context.moduleFiles.length).toEqual(2); + expect(context.moduleFiles[0]).toEqual(mockDirName); + expect(context.moduleFiles[1]).toEqual(mockDirName + '2'); }); }); }); diff --git a/src/preprocess.ts b/src/preprocess.ts index 39dd1228..98bd9a81 100644 --- a/src/preprocess.ts +++ b/src/preprocess.ts @@ -4,7 +4,8 @@ import { basename, dirname, join, relative } from 'path'; import { Logger } from './logger/logger'; import * as Constants from './util/constants'; import { BuildError } from './util/errors'; -import { getBooleanPropertyValue } from './util/helpers'; +import { globAll, GlobResult } from './util/glob-util'; +import { getBooleanPropertyValue, getStringPropertyValue } from './util/helpers'; import { BuildContext, ChangedFile } from './util/interfaces'; import { optimization } from './optimization'; import { deepLinking, deepLinkingUpdate } from './deep-linking'; @@ -26,8 +27,8 @@ export function preprocess(context: BuildContext) { function preprocessWorker(context: BuildContext) { const bundlePromise = bundleCoreComponents(context); const deepLinksPromise = getBooleanPropertyValue(Constants.ENV_PARSE_DEEPLINKS) ? deepLinking(context) : Promise.resolve(); - - return Promise.all([bundlePromise, deepLinksPromise]) + const componentSassPromise = lookUpDefaultIonicComponentPaths(context); + return Promise.all([bundlePromise, deepLinksPromise, componentSassPromise]) .then(() => { if (context.optimizeJs) { return optimization(context, null); @@ -67,3 +68,15 @@ export function preprocessUpdate(changedFiles: ChangedFile[], context: BuildCont return Promise.all(promises); } + +export function lookUpDefaultIonicComponentPaths(context: BuildContext) { + const componentsDirGlob = join(getStringPropertyValue(Constants.ENV_VAR_IONIC_ANGULAR_DIR), 'components', '**', '*.scss'); + const srcDirGlob = join(getStringPropertyValue(Constants.ENV_VAR_SRC_DIR), '**', '*.scss'); + return globAll([componentsDirGlob, srcDirGlob]).then((results: GlobResult[]) => { + const componentPathSet = new Set(); + results.forEach(result => { + componentPathSet.add(result.absolutePath); + }); + context.moduleFiles = Array.from(componentPathSet); + }); +} diff --git a/src/rollup.ts b/src/rollup.ts index 006408ee..650fb9df 100644 --- a/src/rollup.ts +++ b/src/rollup.ts @@ -73,17 +73,6 @@ export function rollupWorker(context: BuildContext, configFile: string): Promise Logger.debug(`bundle.modules: ${bundle.modules.length}`); - // set the module files used in this bundle - // this reference can be used elsewhere in the build (sass) - context.moduleFiles = bundle.modules.map((m) => { - // sometimes, Rollup appends weird prefixes to the path like commonjs:proxy - const index = m.id.indexOf(sep); - if (index >= 0) { - return m.id.substring(index); - } - return m.id; - }); - // cache our bundle for later use if (context.isWatch) { cachedBundle = bundle; @@ -225,4 +214,4 @@ export interface RollupLocationInfo { file: string; line: number; column: number; -} +} \ No newline at end of file diff --git a/src/webpack.ts b/src/webpack.ts index 5a16db09..1001cb5d 100644 --- a/src/webpack.ts +++ b/src/webpack.ts @@ -93,21 +93,6 @@ function webpackBuildComplete(stats: any, context: BuildContext, webpackConfig: Logger.debug('Webpack Dependency Map End'); } - // set the module files used in this bundle - // this reference can be used elsewhere in the build (sass) - const files: string[] = stats.compilation.modules.map((webpackObj: any) => { - if (webpackObj.resource) { - return webpackObj.resource; - } else { - return webpackObj.context; - } - }).filter((path: string) => { - // just make sure the path is not null - return path && path.length > 0; - }); - - context.moduleFiles = files; - return writeBundleFilesToDisk(context); } @@ -244,4 +229,4 @@ export interface WebpackOutputObject { export interface WebpackResolveObject { extensions: string[]; modules: string[]; -} +} \ No newline at end of file