diff --git a/app/angular/package.json b/app/angular/package.json index 0122b7fbe896..fffaf8b4f1ab 100644 --- a/app/angular/package.json +++ b/app/angular/package.json @@ -39,6 +39,7 @@ "react-dom": "^16.4.2", "sass-loader": "^7.1.0", "ts-loader": "^4.5.0", + "tsconfig-paths-webpack-plugin": "^3.2.0", "webpack": "^4.20.0", "zone.js": "^0.8.26" }, diff --git a/app/angular/src/server/angular-cli_config.js b/app/angular/src/server/angular-cli_config.js index 190bb767dd86..41ec13d99c7a 100644 --- a/app/angular/src/server/angular-cli_config.js +++ b/app/angular/src/server/angular-cli_config.js @@ -1,8 +1,45 @@ import path from 'path'; import fs from 'fs'; import { logger } from '@storybook/node-logger'; +import { TsconfigPathsPlugin } from 'tsconfig-paths-webpack-plugin'; import { isBuildAngularInstalled, normalizeAssetPatterns } from './angular-cli_utils'; +function getTsConfigOptions(tsConfigPath) { + const basicOptions = { + options: {}, + fileNames: [], + errors: [], + }; + + if (!fs.existsSync(tsConfigPath)) { + return basicOptions; + } + + const tsConfig = JSON.parse(fs.readFileSync(tsConfigPath, 'utf8')); + const { baseUrl } = tsConfig.compilerOptions || {}; + + if (baseUrl) { + const tsConfigDirName = path.dirname(tsConfigPath); + basicOptions.options.baseUrl = path.resolve(tsConfigDirName, baseUrl); + } + + return basicOptions; +} + +function getAngularCliParts(cliWebpackConfigOptions) { + // eslint-disable-next-line global-require, import/no-extraneous-dependencies + const ngCliConfigFactory = require('@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs'); + + try { + return { + cliCommonConfig: ngCliConfigFactory.getCommonConfig(cliWebpackConfigOptions), + cliStyleConfig: ngCliConfigFactory.getStylesConfig(cliWebpackConfigOptions), + }; + } catch (e) { + return null; + } +} + export function getAngularCliWebpackConfigOptions(dirToSearch) { const fname = path.join(dirToSearch, 'angular.json'); @@ -31,16 +68,16 @@ export function getAngularCliWebpackConfigOptions(dirToSearch) { project.sourceRoot ); + const projectRoot = path.resolve(dirToSearch, project.root); + const tsConfigPath = path.resolve(dirToSearch, projectOptions.tsConfig); + const tsConfig = getTsConfigOptions(tsConfigPath); + return { root: dirToSearch, - projectRoot: path.resolve(dirToSearch, project.root), + projectRoot, + tsConfigPath, + tsConfig, supportES2015: false, - tsConfig: { - options: {}, - fileNames: [], - errors: [], - }, - tsConfigPath: path.resolve(dirToSearch, 'src/tsconfig.app.json'), buildOptions: { ...projectOptions, assets: normalizedAssets, @@ -49,27 +86,26 @@ export function getAngularCliWebpackConfigOptions(dirToSearch) { } export function applyAngularCliWebpackConfig(baseConfig, cliWebpackConfigOptions) { - if (!cliWebpackConfigOptions) return baseConfig; + if (!cliWebpackConfigOptions) { + return baseConfig; + } if (!isBuildAngularInstalled()) { logger.info('=> Using base config because @angular-devkit/build-angular is not installed.'); return baseConfig; } - // eslint-disable-next-line global-require, import/no-extraneous-dependencies - const ngcliConfigFactory = require('@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs'); + const cliParts = getAngularCliParts(cliWebpackConfigOptions); - let cliCommonConfig; - let cliStyleConfig; - try { - cliCommonConfig = ngcliConfigFactory.getCommonConfig(cliWebpackConfigOptions); - cliStyleConfig = ngcliConfigFactory.getStylesConfig(cliWebpackConfigOptions); - } catch (e) { + if (!cliParts) { logger.warn('=> Failed to get angular-cli webpack config.'); return baseConfig; } + logger.info('=> Get angular-cli webpack config.'); + const { cliCommonConfig, cliStyleConfig } = cliParts; + // Don't use storybooks .css/.scss rules because we have to use rules created by @angular-devkit/build-angular // because @angular-devkit/build-angular created rules have include/exclude for global style files. const rulesExcludingStyles = baseConfig.module.rules.filter( @@ -85,7 +121,7 @@ export function applyAngularCliWebpackConfig(baseConfig, cliWebpackConfigOptions .concat(Object.values(cliStyleConfig.entry).reduce((acc, item) => acc.concat(item), [])), }; - const mod = { + const module = { ...baseConfig.module, rules: [...cliStyleConfig.module.rules, ...rulesExcludingStyles], }; @@ -93,11 +129,24 @@ export function applyAngularCliWebpackConfig(baseConfig, cliWebpackConfigOptions // We use cliCommonConfig plugins to serve static assets files. const plugins = [...cliStyleConfig.plugins, ...cliCommonConfig.plugins, ...baseConfig.plugins]; + const resolve = { + ...baseConfig.resolve, + modules: Array.from( + new Set([...baseConfig.resolve.modules, ...cliCommonConfig.resolve.modules]) + ), + plugins: [ + new TsconfigPathsPlugin({ + configFile: cliWebpackConfigOptions.buildOptions.tsConfig, + }), + ], + }; + return { ...baseConfig, entry, - module: mod, + module, plugins, + resolve, resolveLoader: cliCommonConfig.resolveLoader, }; } diff --git a/examples/angular-cli/.storybook/tsconfig.json b/examples/angular-cli/.storybook/tsconfig.json index de9e409b5fbd..6d196e52c50d 100644 --- a/examples/angular-cli/.storybook/tsconfig.json +++ b/examples/angular-cli/.storybook/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../tsconfig.json", + "extends": "../src/tsconfig.app.json", "exclude": [ "../src/test.ts", "../src/**/*.spec.ts" diff --git a/examples/angular-cli/angularshots.test.js b/examples/angular-cli/angularshots.test.js index 7f731c986b0b..41dfc8a015a2 100644 --- a/examples/angular-cli/angularshots.test.js +++ b/examples/angular-cli/angularshots.test.js @@ -2,6 +2,7 @@ import path from 'path'; import initStoryshots, { multiSnapshotWithOptions } from '@storybook/addon-storyshots'; jest.mock('./addon-jest.testresults.json', () => ({}), { virtual: true }); +jest.mock('environments/environment', () => ({}), { virtual: true }); initStoryshots({ framework: 'angular', diff --git a/examples/angular-cli/src/stories/index.ts b/examples/angular-cli/src/stories/index.ts index b7b5494cdff9..59db5a929f60 100644 --- a/examples/angular-cli/src/stories/index.ts +++ b/examples/angular-cli/src/stories/index.ts @@ -2,6 +2,11 @@ import { storiesOf } from '@storybook/angular'; import { Welcome, Button } from '@storybook/angular/demo'; import { moduleMetadata } from '@storybook/angular'; import { linkTo } from '@storybook/addon-links'; +import { environment } from 'environments/environment'; + +if (environment) { + // This ensures that the basePath typeScript feature works with storybook +} storiesOf('Welcome', module).add('to Storybook', () => ({ template: ``, diff --git a/lib/cli/generators/ANGULAR/template/.storybook/tsconfig.json b/lib/cli/generators/ANGULAR/template/.storybook/tsconfig.json index 62ffb8ca0e23..15995ca772d7 100644 --- a/lib/cli/generators/ANGULAR/template/.storybook/tsconfig.json +++ b/lib/cli/generators/ANGULAR/template/.storybook/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../tsconfig.json", + "extends": "../src/tsconfig.app.json", "exclude": [ "../src/test.ts", "../src/**/*.spec.ts", diff --git a/yarn.lock b/yarn.lock index 267d11a5839a..0bea3a3f32eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1978,6 +1978,11 @@ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-23.3.1.tgz#a4319aedb071d478e6f407d1c4578ec8156829cf" integrity sha512-/UMY+2GkOZ27Vrc51pqC5J8SPd39FKt7kkoGAtWJ8s4msj0b15KehDWIiJpWY3/7tLxBQLLzJhIBhnEsXdzpgw== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + "@types/node@*": version "10.9.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.9.2.tgz#f0ab8dced5cd6c56b26765e1c0d9e4fdcc9f2a00" @@ -7694,6 +7699,11 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge@^2.0.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== + default-gateway@^2.6.0: version "2.7.2" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-2.7.2.tgz#b7ef339e5e024b045467af403d50348db4642d0f" @@ -13716,7 +13726,7 @@ json5@^0.5.0, json5@^0.5.1: resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= -json5@^1.0.0: +json5@^1.0.0, json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== @@ -22587,6 +22597,26 @@ ts-node@~7.0.0: source-map-support "^0.5.6" yn "^2.0.0" +tsconfig-paths-webpack-plugin@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.2.0.tgz#6e70bd42915ad0efb64d3385163f0c1270f3e04d" + integrity sha512-S/gOOPOkV8rIL4LurZ1vUdYCVgo15iX9ZMJ6wx6w2OgcpT/G4wMyHB6WM+xheSqGMrWKuxFul+aXpCju3wmj/g== + dependencies: + chalk "^2.3.0" + enhanced-resolve "^4.0.0" + tsconfig-paths "^3.4.0" + +tsconfig-paths@^3.4.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.6.0.tgz#f14078630d9d6e8b1dc690c1fc0cfb9cd0663891" + integrity sha512-mrqQIP2F4e03aMTCiPdedCIT300//+q0ET53o5WqqtQjmEICxP9yfz/sHTpPqXpssuJEzODsEzJaLRaf5J2X1g== + dependencies: + "@types/json5" "^0.0.29" + deepmerge "^2.0.1" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + tsickle@^0.32.1: version "0.32.1" resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.32.1.tgz#f16e94ba80b32fc9ebe320dc94fbc2ca7f3521a5"