mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
341 lines
8.9 KiB
TypeScript
341 lines
8.9 KiB
TypeScript
import { DefinePlugin, HotModuleReplacementPlugin } from 'webpack';
|
|
import Config from 'webpack-chain';
|
|
import { resolve } from 'path';
|
|
|
|
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
|
|
import FilterWarningsPlugin from 'webpack-filter-warnings-plugin';
|
|
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
|
import TerserPlugin from 'terser-webpack-plugin';
|
|
|
|
// import { WatchStateLoggerPlugin } from '../plugins/WatchStateLoggerPlugin';
|
|
import { getProjectFilePath, getProjectRootPath } from '../helpers/project';
|
|
import { PlatformSuffixPlugin } from '../plugins/PlatformSuffixPlugin';
|
|
import { addCopyRule, applyCopyRules } from '../helpers/copyRules';
|
|
import { WatchStatePlugin } from '../plugins/WatchStatePlugin';
|
|
import { hasDependency } from '../helpers/dependencies';
|
|
import { applyDotEnvPlugin } from '../helpers/dotEnv';
|
|
import { env as _env, IWebpackEnv } from '../index';
|
|
import { getIPS } from '../helpers/host';
|
|
import {
|
|
getPlatformName,
|
|
getAbsoluteDistPath,
|
|
getEntryDirPath,
|
|
getEntryPath,
|
|
} from '../helpers/platform';
|
|
|
|
export default function (config: Config, env: IWebpackEnv = _env): Config {
|
|
const entryPath = getEntryPath();
|
|
const platform = getPlatformName();
|
|
const mode = env.production ? 'production' : 'development';
|
|
|
|
// set mode
|
|
config.mode(mode);
|
|
|
|
// config.stats({
|
|
// logging: 'verbose'
|
|
// })
|
|
|
|
// package.json is generated by the CLI with runtime options
|
|
// this ensures it's not included in the bundle, but rather
|
|
// resolved at runtime
|
|
config.externals(['package.json', '~/package.json']);
|
|
|
|
// todo: devtool
|
|
config.devtool('inline-source-map');
|
|
|
|
// todo: figure out easiest way to make "node" target work in ns
|
|
// rather than the custom ns target implementation that's hard to maintain
|
|
// appears to be working - but we still have to deal with HMR
|
|
config.target('node');
|
|
|
|
config
|
|
.entry('bundle')
|
|
// ensure we load nativescript globals first
|
|
.add('@nativescript/core/globals/index.js')
|
|
.add(entryPath);
|
|
|
|
// Add android app components to the bundle to SBG can generate the java classes
|
|
if (platform === 'android') {
|
|
const appComponents = env.appComponents || [];
|
|
appComponents.push('@nativescript/core/ui/frame');
|
|
appComponents.push('@nativescript/core/ui/frame/activity');
|
|
appComponents.map((component) => {
|
|
config.entry('bundle').add(component);
|
|
});
|
|
}
|
|
|
|
// inspector_modules
|
|
config.when(shouldIncludeInspectorModules(), (config) => {
|
|
config
|
|
.entry('tns_modules/inspector_modules')
|
|
.add('@nativescript/core/inspector_modules');
|
|
});
|
|
|
|
config.output
|
|
.path(getAbsoluteDistPath())
|
|
.pathinfo(false)
|
|
.publicPath('')
|
|
.libraryTarget('commonjs')
|
|
.globalObject('global')
|
|
.set('clean', true);
|
|
|
|
config.watchOptions({
|
|
ignored: [
|
|
`${getProjectFilePath('platforms')}/**`,
|
|
`${env.appResourcesPath ?? getProjectFilePath('App_Resources')}/**`
|
|
]
|
|
})
|
|
|
|
// Set up Terser options
|
|
config.optimization.minimizer('TerserPlugin').use(TerserPlugin, [
|
|
{
|
|
terserOptions: {
|
|
compress: {
|
|
collapse_vars: platform !== 'android',
|
|
sequences: platform !== 'android',
|
|
},
|
|
// todo: move into vue.ts if not required in other flavors?
|
|
keep_fnames: true,
|
|
},
|
|
},
|
|
]);
|
|
|
|
config.optimization.splitChunks({
|
|
cacheGroups: {
|
|
defaultVendor: {
|
|
test: /[\\/]node_modules[\\/]/,
|
|
priority: -10,
|
|
name: 'vendor',
|
|
chunks: 'all',
|
|
},
|
|
},
|
|
});
|
|
|
|
// look for loaders in
|
|
// - node_modules/@nativescript/webpack/dist/loaders
|
|
// - node_modules
|
|
// allows for cleaner rules, without having to specify full paths to loaders
|
|
config.resolveLoader.modules
|
|
.add('node_modules/@nativescript/webpack/dist/loaders')
|
|
.add('node_modules');
|
|
|
|
config.resolve.extensions
|
|
.add(`.${platform}.ts`)
|
|
.add('.ts')
|
|
.add(`.${platform}.js`)
|
|
.add('.js')
|
|
.add(`.${platform}.css`)
|
|
.add('.css')
|
|
.add(`.${platform}.scss`)
|
|
.add('.scss')
|
|
.add(`.${platform}.json`)
|
|
.add('.json');
|
|
|
|
// base aliases
|
|
config.resolve.alias.set('~', getEntryDirPath()).set('@', getEntryDirPath());
|
|
|
|
// resolve symlinks
|
|
config.resolve.symlinks(true);
|
|
|
|
config.module.rule('bundle')
|
|
.enforce('post')
|
|
.test(entryPath)
|
|
.use('nativescript-hot-loader')
|
|
.loader('nativescript-hot-loader')
|
|
.options({
|
|
injectHMRRuntime: true
|
|
})
|
|
|
|
// set up ts support
|
|
config.module
|
|
.rule('ts')
|
|
.test([/\.ts$/])
|
|
.use('ts-loader')
|
|
.loader('ts-loader')
|
|
.options({
|
|
// todo: perhaps we can provide a default tsconfig
|
|
// and use that if the project doesn't have one?
|
|
// configFile: '',
|
|
transpileOnly: true,
|
|
allowTsInNodeModules: true,
|
|
compilerOptions: {
|
|
sourceMap: true,
|
|
declaration: false,
|
|
},
|
|
getCustomTransformers() {
|
|
return {
|
|
before: [require('../transformers/NativeClass').default],
|
|
};
|
|
},
|
|
});
|
|
|
|
// Use Fork TS Checker to do type checking in a separate non-blocking process
|
|
config.when(hasDependency('typescript'), (config) => {
|
|
config
|
|
.plugin('ForkTsCheckerWebpackPlugin')
|
|
.use(ForkTsCheckerWebpackPlugin, [
|
|
{
|
|
typescript: {
|
|
memoryLimit: 4096,
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
// set up js
|
|
// todo: do we need babel-loader? It's useful to support it
|
|
config.module
|
|
.rule('js')
|
|
.test(/\.js$/)
|
|
.exclude.add(/node_modules/)
|
|
.end()
|
|
.use('babel-loader')
|
|
.loader('babel-loader')
|
|
.options({
|
|
generatorOpts: {
|
|
compact: false,
|
|
},
|
|
});
|
|
|
|
config.module
|
|
.rule('workers')
|
|
.test(/\.(js|ts)$/)
|
|
.exclude.add(/node_modules/)
|
|
.end()
|
|
.use('nativescript-worker-loader')
|
|
.loader('nativescript-worker-loader')
|
|
|
|
// default PostCSS options to use
|
|
// projects can change settings
|
|
// via postcss.config.js
|
|
const postCSSOptions = {
|
|
postcssOptions: {
|
|
plugins: [
|
|
// inlines @imported stylesheets
|
|
'postcss-import',
|
|
],
|
|
},
|
|
};
|
|
|
|
// set up css
|
|
config.module
|
|
.rule('css')
|
|
.test(/\.css$/)
|
|
.use('apply-css-loader')
|
|
.loader('apply-css-loader')
|
|
.end()
|
|
.use('css2json-loader')
|
|
.loader('css2json-loader')
|
|
.end()
|
|
.use('postcss-loader')
|
|
.loader('postcss-loader')
|
|
.options(postCSSOptions);
|
|
|
|
// set up scss
|
|
config.module
|
|
.rule('scss')
|
|
.test(/\.scss$/)
|
|
.use('apply-css-loader')
|
|
.loader('apply-css-loader')
|
|
.end()
|
|
.use('css2json-loader')
|
|
.loader('css2json-loader')
|
|
.end()
|
|
.use('postcss-loader')
|
|
.loader('postcss-loader')
|
|
.options(postCSSOptions)
|
|
.end()
|
|
.use('sass-loader')
|
|
.loader('sass-loader');
|
|
|
|
// config.plugin('NormalModuleReplacementPlugin').use(NormalModuleReplacementPlugin, [
|
|
// /.*/,
|
|
// request => {
|
|
// if (new RegExp(`\.${platform}\..+$`).test(request.request)) {
|
|
// request.rawRequest = request.rawRequest.replace(`.${platform}.`, '.')
|
|
// console.log(request)
|
|
// }
|
|
// }
|
|
// ])
|
|
|
|
config.plugin('PlatformSuffixPlugin').use(PlatformSuffixPlugin, [
|
|
{
|
|
platform,
|
|
},
|
|
]);
|
|
|
|
// Filter common undesirable warnings
|
|
config.plugin('FilterWarningsPlugin').use(FilterWarningsPlugin, [
|
|
{
|
|
/**
|
|
* This rule hides
|
|
* +-------------------------------------------------------------------------------+
|
|
* | WARNING in ./node_modules/@angular/core/fesm2015/core.js 29714:15-102 |
|
|
* | System.import() is deprecated and will be removed soon. Use import() instead. |
|
|
* | For more info visit https://webpack.js.org/guides/code-splitting/ |
|
|
* +-------------------------------------------------------------------------------+
|
|
*/
|
|
exclude: /System.import\(\) is deprecated/,
|
|
},
|
|
]);
|
|
|
|
// todo: refine defaults
|
|
config.plugin('DefinePlugin').use(DefinePlugin, [
|
|
{
|
|
__DEV__: mode === 'development',
|
|
__NS_WEBPACK__: true,
|
|
__NS_DEV_HOST_IPS__:
|
|
mode === 'development' ? JSON.stringify(getIPS()) : `[]`,
|
|
__CSS_PARSER__: JSON.stringify('css-tree'), // todo: replace from config value
|
|
__ANDROID__: platform === 'android',
|
|
__IOS__: platform === 'ios',
|
|
/* for compat only */ 'global.isAndroid': platform === 'android',
|
|
/* for compat only */ 'global.isIOS': platform === 'ios',
|
|
process: 'global.process',
|
|
|
|
// todo: ?!?!
|
|
// profile: '() => {}',
|
|
},
|
|
]);
|
|
|
|
// enable DotEnv
|
|
applyDotEnvPlugin(config);
|
|
|
|
// set up default copy rules
|
|
addCopyRule('assets/**');
|
|
addCopyRule('fonts/**');
|
|
addCopyRule('**/*.+(jpg|png)');
|
|
|
|
applyCopyRules(config);
|
|
|
|
// add the WatchStateLogger plugin used to notify the CLI of build state
|
|
// config.plugin('WatchStateLoggerPlugin').use(WatchStateLoggerPlugin);
|
|
config.plugin('WatchStatePlugin').use(WatchStatePlugin);
|
|
|
|
config.when(env.hmr, (config) => {
|
|
config.plugin('HotModuleReplacementPlugin').use(HotModuleReplacementPlugin);
|
|
});
|
|
|
|
config.when(env.report, (config) => {
|
|
const projectRoot = getProjectRootPath();
|
|
config.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin, [
|
|
{
|
|
analyzerMode: 'static',
|
|
generateStatsFile: true,
|
|
openAnalyzer: false,
|
|
reportFilename: resolve(projectRoot, 'report', 'report.html'),
|
|
statsFilename: resolve(projectRoot, 'report', 'stats.json'),
|
|
},
|
|
]);
|
|
});
|
|
|
|
return config;
|
|
}
|
|
|
|
function shouldIncludeInspectorModules(): boolean {
|
|
const platform = getPlatformName();
|
|
// todo: check if core modules are external
|
|
// todo: check if we are testing
|
|
return platform === 'ios';
|
|
}
|