How to modify babel-preset-env configuration in laravel-mix - laravel-mix

Laravel Mix Version: 1.4.2
Node Version (node -v): v8.4.0
NPM Version (npm -v): 5.3.0
OS: Mac
Description:
In src/config.js there is:
babel: function () {
let options = {};
tap(Mix.paths.root('.babelrc'), babelrc => {
if (File.exists(babelrc)) {
options = JSON.parse(File.find(babelrc).read());
}
});
let defaultOptions = {
cacheDirectory: true,
presets: [
['env', {
'modules': false,
'targets': {
'browsers': ['> 2%'],
uglify: true
}
}]
]
};
if (this.react) {
defaultOptions.presets.push('react');
}
return webpackMerge.smart(defaultOptions, options);
},
Steps To Reproduce:
In my .babelrc I have
{
"presets": [
["env", {
"targets": {
"browsers": ["> 5%"],
"uglify": false
}
}]
]
}
However, this is just concatenating this as another 'env' preset and it isn't being used. How can I modify the original env preset?

Related

CKEditor5 v.32 on Laravel 8 / Laravel Mix 6

Does anybody have a working webpack.mix.js config for CKEditor5 32 on Laravel 8 (Laravel Mix 6 and Webpack 5) already? I have been banging my head to the wall for the past 8 hours and still could not manage to make it work.
Here is the console error I receive.
Before, when I was using Laravel Mix 5 and Webpack 4, this config solution seemed to be working.
But now all I get are a bunch of the same errors during npm compilation.
Config's snipped that worked for me
const CKEditorWebpackPlugin = require('#ckeditor/ckeditor5-dev-webpack-plugin');
const CKEditorStyles = require('#ckeditor/ckeditor5-dev-utils').styles;
//Includes SVGs and CSS files from "node_modules/ckeditor5-*" and any other custom directories
const CKEditorRegex = {
svg: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/, //If you have any custom plugins in your project with SVG icons, include their path in this regex as well.
css: /ckeditor5-[^/\\]+[/\\].+\.css$/,
};
//Exclude CKEditor regex from mix's default rules
Mix.listen('configReady', config => {
const rules = config.module.rules;
const targetSVG = (/(\.(png|jpe?g|gif|webp|avif)$|^((?!font).)*\.svg$)/).toString();
const targetFont = (/(\.(woff2?|ttf|eot|otf)$|font.*\.svg$)/).toString();
const targetCSS = (/\.p?css$/).toString();
rules.forEach(rule => {
let test = rule.test.toString();
if ([targetSVG, targetFont].includes(rule.test.toString())) {
rule.exclude = CKEditorRegex.svg;
} else if (test === targetCSS) {
rule.exclude = CKEditorRegex.css;
}
});
});
mix.webpackConfig({
plugins: [
new CKEditorWebpackPlugin({
language: 'en',
addMainLanguageTranslationsToAllAssets: true
}),
],
module: {
rules: [
{
test: CKEditorRegex.svg,
use: ['raw-loader']
},
{
test: CKEditorRegex.css,
use: [
{
loader: 'style-loader',
options: {
injectType: 'singletonStyleTag',
attributes: {
'data-cke': true
}
}
},
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: CKEditorStyles.getPostCssConfig({
themeImporter: {
themePath: require.resolve('#ckeditor/ckeditor5-theme-lark')
},
minify: true
})
}
}
]
}
]
}
});
Specs:
node v.16.11.1
npm v.8.0.0
Laravel v.8.77.1
package.json
"laravel-mix": "6.0.40",
"postcss-loader": "^6.2.1",
"raw-loader": "^4.0.1",
"sass": "^1.49.4",
"sass-loader": "^12.4.0",
"style-loader": "^2.0.0"
The Mix.listen() was deprecated and will go away in a future release. should replaced by mix.override().
Thanks #bakis.
This is the only working version after hours of searching. Exclude CKEditor regex from mix's default rules is the key neglected.
/** ckeditor 5 webpack config ****/
const CKEditorWebpackPlugin = require('#ckeditor/ckeditor5-dev-webpack-plugin');
const CKEditorStyles = require('#ckeditor/ckeditor5-dev-utils').styles;
//Includes SVGs and CSS files from "node_modules/ckeditor5-*" and any other custom directories
const CKEditorRegex = {
svg: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/, //If you have any custom plugins in your project with SVG icons, include their path in this regex as well.
css: /ckeditor5-[^/\\]+[/\\].+\.css$/,
};
mix.webpackConfig({
plugins: [
new CKEditorWebpackPlugin({
language: 'en',
addMainLanguageTranslationsToAllAssets: true
}),
],
module: {
rules: [
{
test: CKEditorRegex.svg,
use: ['raw-loader']
},
{
test: CKEditorRegex.css,
use: [
{
loader: 'style-loader',
options: {
injectType: 'singletonStyleTag',
attributes: {
'data-cke': true
}
}
},
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: CKEditorStyles.getPostCssConfig({
themeImporter: {
themePath: require.resolve('#ckeditor/ckeditor5-theme-lark')
},
minify: true
})
}
}
]
}
]
}
});
//Exclude CKEditor regex from mix's default rules
mix.override(config => {
const rules = config.module.rules;
const targetSVG = (/(\.(png|jpe?g|gif|webp|avif)$|^((?!font).)*\.svg$)/).toString();
const targetFont = (/(\.(woff2?|ttf|eot|otf)$|font.*\.svg$)/).toString();
const targetCSS = (/\.p?css$/).toString();
rules.forEach(rule => {
let test = rule.test.toString();
if ([targetSVG, targetFont].includes(rule.test.toString())) {
rule.exclude = CKEditorRegex.svg;
} else if (test === targetCSS) {
rule.exclude = CKEditorRegex.css;
}
});
});

SCSS Modules not properly loading in Storybook for my Nextjs app

Working on a new project using Nextjs and Storybook. We are using SCSS modules to style our components, and they work just fine in the actual app on the browser, but they won't link up in the stories themselves. Here are a few simple snippets to show where I'm at right now:
Component:
import React from 'react'
import styles from './VideoEntryTile.module.scss'
const VideoEntryTile: React.FC = () => {
return (
// This displays properly in the browser but not storybook
<div className={styles.container}>
<p>Hello</p>
</div>
)
}
export default VideoEntryTile
SCSS module:
.container {
background-color: blueviolet;
}
Component story:
import React from 'react';
import { ComponentStory, ComponentMeta } from '#storybook/react';
import VideoEntryTile from './VideoEntryTile';
export default {
title: 'Video Entry Tile',
component: VideoEntryTile,
argTypes: {
},
} as ComponentMeta<typeof VideoEntryTile>;
const Template: ComponentStory<typeof VideoEntryTile> = (args) => <VideoEntryTile {...args} />;
export const Primary = Template.bind({});
Primary.args = {};
./storybook/main.js:
module.exports = {
core: {
builder: 'webpack5',
},
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)",
"../src/components/**/*.stories.tsx"
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-essentials",
{
name: '#storybook/preset-scss',
options: {
sassLoaderOptions: {
modules: true
}
}
}
],
"framework": "#storybook/react"
}
Can anyone tell me where I'm going wrong? Thanks.
Create a file called scss-preset.js in .storybook:
// Copied from https://github.com/storybookjs/presets/blob/master/packages/preset-scss/index.js
function wrapLoader(loader, options) {
if (options === false) {
return [];
}
return [
{
loader,
options,
},
];
}
function webpack(webpackConfig = {}, options = {}) {
const { module = {} } = webpackConfig;
const {
styleLoaderOptions,
cssLoaderOptions,
sassLoaderOptions,
rule = {},
} = options;
return {
...webpackConfig,
module: {
...module,
rules: [
...(module.rules || []),
{
test: /(?<!module)\.s[ca]ss$/,
...rule,
use: [
...wrapLoader('style-loader', styleLoaderOptions),
...wrapLoader('css-loader', {
...cssLoaderOptions,
modules: false,
}),
...wrapLoader('sass-loader', sassLoaderOptions),
],
},
{
test: /\.module\.s[ca]ss$/,
...rule,
use: [
...wrapLoader('style-loader', styleLoaderOptions),
...wrapLoader('css-loader', {
...cssLoaderOptions,
modules: true,
}),
...wrapLoader('sass-loader', sassLoaderOptions),
],
},
],
},
};
}
module.exports = { webpack };
This is going through each scss file and, if it's a module.scss file, processing it differently than the ones that aren't.
in main.js, add presets: [path.resolve("./.storybook/scss-preset.js")], to module.exports. Should be all you need.
Make sure you have installed sass
npm install sass --save
Install scss preset
npm install #storybook/preset-scss --save
Add it to the addons list inside your .storybook/main.js
addons: ['#storybook/preset-scss',]

Using iconfont-webpack-plugin with Laravel Mix

I'm new to webpack and trying to add a custom icon font builder to a Laravel project. The iconfont library is available at iconfont-webpack-plugin, and added to webpack.config.js as follows:
const IconfontWebpackPlugin = require('iconfont-webpack-plugin');
module: {
rules: [
{
test: /\.css$/,
use: [
'css-loader',
{
loader: 'postcss-loader',
postcssOptions: (loader) => {
return {
plugins: [
new IconfontWebpackPlugin({
resolve: loader.resolve,
fontNamePrefix: 'custom-',
enforcedSvgHeight: 3000,
})
]
};
}
}
]
}
]
}
In Laravel Mix I'm using the mix.webpackConfig() function as follows:
const IconfontWebpackPlugin = require('iconfont-webpack-plugin');
mix.webpackConfig({
module: {
rules: [
{
test: /\.css$/,
use: [
'css-loader',
{
loader: 'postcss-loader',
postcssOptions: (loader) => {
return {
plugins: [
new IconfontWebpackPlugin({
resolve: loader.resolve,
fontNamePrefix: 'custom-',
enforcedSvgHeight: 3000,
})
]
};
}
}
]
}
]
}
});
This is giving a build error:
Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
- configuration.module.rules[12].use[1] has an unknown property 'postcssOptions'. These properties are valid:
object { ident?, loader?, options? }
What is the correct way to do this in Laravel Mix?

Nativescript Angular code sharing project problem with Webpack

I have created a code-sharing projects with Angular 8.30 and Nativescript.
When I run ng serve, the app builds ok. However with tns run android I have problems with Webpack.
Here is the error:
Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
- options[0] misses the property 'patterns'. Should be:
[non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)
- options[1] misses the property 'patterns'. Should be:
[non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)
- options[2] misses the property 'patterns'. Should be:
[non-empty string | object { from, to?, context?, globOptions?, toType?, force?, flatten?, transform?, cacheTransform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)
ValidationError: Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
at validate (C:\Users\garma\Desktop\test--project\node_modules\schema-utils\dist\validate.js:96:11)
at new CopyPlugin (C:\Users\garma\Desktop\test--project\node_modules\copy-webpack-plugin\dist\index.js:24:30)
at module.exports (C:\Users\garma\Desktop\test--project\webpack.config.js:302:13)
at handleFunction (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\prepareOptions.js:23:13)
at prepareOptions (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\prepareOptions.js:9:5)
at requireConfig (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\convert-argv.js:136:14)
at C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\convert-argv.js:142:17
at Array.forEach (<anonymous>)
at module.exports (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\convert-argv.js:140:15)
at C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\cli.js:241:39
at Object.parse (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\node_modules\yargs\yargs.js:567:18)
at C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\cli.js:219:8
at Object.<anonymous> (C:\Users\garma\Desktop\test--project\node_modules\webpack-cli\bin\cli.js:538:3)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)
at Module.require (internal/modules/cjs/loader.js:1026:19)
at require (internal/modules/cjs/helpers.js:72:18)
at Object.<anonymous> (C:\Users\garma\Desktop\test--project\node_modules\webpack\bin\webpack.js:156:2)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47
Executing webpack failed with exit code 1.
This is my webpack.config.js file:
const { join, relative, resolve, sep, dirname } = require("path");
const webpack = require("webpack");
const nsWebpack = require("nativescript-dev-webpack");
const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
const { nsReplaceBootstrap } = require("nativescript-dev-webpack/transformers/ns-replace-bootstrap");
const { nsReplaceLazyLoader } = require("nativescript-dev-webpack/transformers/ns-replace-lazy-loader");
const { nsSupportHmrNg } = require("nativescript-dev-webpack/transformers/ns-support-hmr-ng");
const { getMainModulePath } = require("nativescript-dev-webpack/utils/ast-utils");
const { getNoEmitOnErrorFromTSConfig, getCompilerOptionsFromTSConfig } = require("nativescript-dev-webpack/utils/tsconfig-utils");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin");
const TerserPlugin = require("terser-webpack-plugin");
const { getAngularCompilerPlugin } = require("nativescript-dev-webpack/plugins/NativeScriptAngularCompilerPlugin");
const hashSalt = Date.now().toString();
module.exports = env => {
// Add your custom Activities, Services and other Android app components here.
const appComponents = env.appComponents || [];
appComponents.push(...[
"tns-core-modules/ui/frame",
"tns-core-modules/ui/frame/activity",
]);
const platform = env && (env.android && "android" || env.ios && "ios" || env.platform);
if (!platform) {
throw new Error("You need to provide a target platform!");
}
const AngularCompilerPlugin = getAngularCompilerPlugin(platform);
const projectRoot = __dirname;
// Default destination inside platforms/<platform>/...
const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));
const {
// The 'appPath' and 'appResourcesPath' values are fetched from
// the nsconfig.json configuration file.
appPath = "src",
appResourcesPath = "App_Resources",
// You can provide the following flags when running 'tns run android|ios'
aot, // --env.aot
snapshot, // --env.snapshot,
production, // --env.production
uglify, // --env.uglify
report, // --env.report
sourceMap, // --env.sourceMap
hiddenSourceMap, // --env.hiddenSourceMap
hmr, // --env.hmr,
unitTesting, // --env.unitTesting
verbose, // --env.verbose
snapshotInDocker, // --env.snapshotInDocker
skipSnapshotTools, // --env.skipSnapshotTools
compileSnapshot // --env.compileSnapshot
} = env;
const useLibs = compileSnapshot;
const isAnySourceMapEnabled = !!sourceMap || !!hiddenSourceMap;
const externals = nsWebpack.getConvertedExternals(env.externals);
const appFullPath = resolve(projectRoot, appPath);
const tsConfigName = "tsconfig.tns.json";
const tsConfigPath = join(__dirname, tsConfigName);
const hasRootLevelScopedModules = nsWebpack.hasRootLevelScopedModules({ projectDir: projectRoot });
const hasRootLevelScopedAngular = nsWebpack.hasRootLevelScopedAngular({ projectDir: projectRoot });
let coreModulesPackageName = "tns-core-modules";
const alias = env.alias || {};
alias['~'] = appFullPath;
const compilerOptions = getCompilerOptionsFromTSConfig(tsConfigPath);
if (hasRootLevelScopedModules) {
coreModulesPackageName = "#nativescript/core";
alias["tns-core-modules"] = coreModulesPackageName;
nsWebpack.processTsPathsForScopedModules({ compilerOptions });
}
if (hasRootLevelScopedAngular) {
alias["nativescript-angular"] = "#nativescript/angular";
nsWebpack.processTsPathsForScopedAngular({ compilerOptions });
}
const appResourcesFullPath = resolve(projectRoot, appResourcesPath);
const entryModule = `${nsWebpack.getEntryModule(appFullPath, platform)}.ts`;
const entryPath = `.${sep}${entryModule}`;
const entries = env.entries || {};
entries.bundle = entryPath;
const areCoreModulesExternal = Array.isArray(env.externals) && env.externals.some(e => e.indexOf("tns-core-modules") > -1);
if (platform === "ios" && !areCoreModulesExternal) {
entries["tns_modules/tns-core-modules/inspector_modules"] = "inspector_modules";
};
const ngCompilerTransformers = [];
const additionalLazyModuleResources = [];
if (aot) {
ngCompilerTransformers.push(nsReplaceBootstrap);
}
if (hmr) {
ngCompilerTransformers.push(nsSupportHmrNg);
}
// when "#angular/core" is external, it's not included in the bundles. In this way, it will be used
// directly from node_modules and the Angular modules loader won't be able to resolve the lazy routes
// fixes https://github.com/NativeScript/nativescript-cli/issues/4024
if (env.externals && env.externals.indexOf("#angular/core") > -1) {
const appModuleRelativePath = getMainModulePath(resolve(appFullPath, entryModule), tsConfigName);
if (appModuleRelativePath) {
const appModuleFolderPath = dirname(resolve(appFullPath, appModuleRelativePath));
// include the lazy loader inside app module
ngCompilerTransformers.push(nsReplaceLazyLoader);
// include the new lazy loader path in the allowed ones
additionalLazyModuleResources.push(appModuleFolderPath);
}
}
const ngCompilerPlugin = new AngularCompilerPlugin({
hostReplacementPaths: nsWebpack.getResolver([platform, "tns"]),
platformTransformers: ngCompilerTransformers.map(t => t(() => ngCompilerPlugin, resolve(appFullPath, entryModule), projectRoot)),
mainPath: join(appFullPath, entryModule),
tsConfigPath,
skipCodeGeneration: !aot,
sourceMap: !!isAnySourceMapEnabled,
additionalLazyModuleResources: additionalLazyModuleResources,
compilerOptions: { paths: compilerOptions.paths }
});
let sourceMapFilename = nsWebpack.getSourceMapFilename(hiddenSourceMap, __dirname, dist);
const itemsToClean = [`${dist}/**/*`];
if (platform === "android") {
itemsToClean.push(`${join(projectRoot, "platforms", "android", "app", "src", "main", "assets", "snapshots")}`);
itemsToClean.push(`${join(projectRoot, "platforms", "android", "app", "build", "configurations", "nativescript-android-snapshot")}`);
}
const noEmitOnErrorFromTSConfig = getNoEmitOnErrorFromTSConfig(join(projectRoot, tsConfigName));
nsWebpack.processAppComponents(appComponents, platform);
const config = {
mode: production ? "production" : "development",
context: appFullPath,
externals,
watchOptions: {
ignored: [
appResourcesFullPath,
// Don't watch hidden files
"**/.*",
]
},
target: nativescriptTarget,
entry: entries,
output: {
pathinfo: false,
path: dist,
sourceMapFilename,
libraryTarget: "commonjs2",
filename: "[name].js",
globalObject: "global",
hashSalt
},
resolve: {
extensions: [".ts", ".js", ".scss", ".css"],
// Resolve {N} system modules from tns-core-modules
modules: [
resolve(__dirname, `node_modules/${coreModulesPackageName}`),
resolve(__dirname, "node_modules"),
`node_modules/${coreModulesPackageName}`,
"node_modules",
],
alias,
symlinks: true
},
resolveLoader: {
symlinks: false
},
node: {
// Disable node shims that conflict with NativeScript
"http": false,
"timers": false,
"setImmediate": false,
"fs": "empty",
"__dirname": false,
},
devtool: hiddenSourceMap ? "hidden-source-map" : (sourceMap ? "inline-source-map" : "none"),
optimization: {
runtimeChunk: "single",
noEmitOnErrors: noEmitOnErrorFromTSConfig,
splitChunks: {
cacheGroups: {
vendor: {
name: "vendor",
chunks: "all",
test: (module, chunks) => {
const moduleName = module.nameForCondition ? module.nameForCondition() : '';
return /[\\/]node_modules[\\/]/.test(moduleName) ||
appComponents.some(comp => comp === moduleName);
},
enforce: true,
},
}
},
minimize: !!uglify,
minimizer: [
new TerserPlugin({
parallel: true,
cache: true,
sourceMap: isAnySourceMapEnabled,
terserOptions: {
output: {
comments: false,
semicolons: !isAnySourceMapEnabled
},
compress: {
// The Android SBG has problems parsing the output
// when these options are enabled
'collapse_vars': platform !== "android",
sequences: platform !== "android",
}
}
})
],
},
module: {
rules: [
{
include: join(appFullPath, entryPath),
use: [
// Require all Android app components
platform === "android" && {
loader: "nativescript-dev-webpack/android-app-components-loader",
options: { modules: appComponents }
},
{
loader: "nativescript-dev-webpack/bundle-config-loader",
options: {
angular: true,
loadCss: !snapshot, // load the application css if in debug mode
unitTesting,
appFullPath,
projectRoot,
ignoredFiles: nsWebpack.getUserDefinedEntries(entries, platform)
}
},
].filter(loader => !!loader)
},
{ test: /\.html$|\.xml$/, use: "raw-loader" },
{
test: /[\/|\\]app\.css$/,
use: [
"nativescript-dev-webpack/style-hot-loader",
{
loader: "nativescript-dev-webpack/css2json-loader",
options: { useForImports: true }
}
]
},
{
test: /[\/|\\]app\.scss$/,
use: [
"nativescript-dev-webpack/style-hot-loader",
{
loader: "nativescript-dev-webpack/css2json-loader",
options: { useForImports: true }
},
"sass-loader"
]
},
// Angular components reference css files and their imports using raw-loader
{ test: /\.css$/, exclude: /[\/|\\]app\.css$/, use: "raw-loader" },
{ test: /\.scss$/, exclude: /[\/|\\]app\.scss$/, use: ["raw-loader", "resolve-url-loader", "sass-loader"] },
{
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
use: [
"nativescript-dev-webpack/moduleid-compat-loader",
"nativescript-dev-webpack/lazy-ngmodule-hot-loader",
"#ngtools/webpack",
]
},
// Mark files inside `#angular/core` as using SystemJS style dynamic imports.
// Removing this will cause deprecation warnings to appear.
{
test: /[\/\\]#angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true },
},
],
},
plugins: [
// Define useful constants like TNS_WEBPACK
new webpack.DefinePlugin({
"global.TNS_WEBPACK": "true",
"process": "global.process",
}),
// Remove all files from the out dir.
new CleanWebpackPlugin(itemsToClean, { verbose: !!verbose }),
// Copy assets to out dir. Add your own globs as needed.
new CopyWebpackPlugin([
{ from: { glob: "fonts/**" } },
{ from: { glob: "**/*.jpg" } },
{ from: { glob: "**/*.png" } },
], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
new nsWebpack.GenerateNativeScriptEntryPointsPlugin("bundle"),
// For instructions on how to set up workers with webpack
// check out https://github.com/nativescript/worker-loader
new NativeScriptWorkerPlugin(),
ngCompilerPlugin,
// Does IPC communication with the {N} CLI to notify events when running in watch mode.
new nsWebpack.WatchStateLoggerPlugin(),
],
};
if (report) {
// Generate report files for bundles content
config.plugins.push(new BundleAnalyzerPlugin({
analyzerMode: "static",
openAnalyzer: false,
generateStatsFile: true,
reportFilename: resolve(projectRoot, "report", `report.html`),
statsFilename: resolve(projectRoot, "report", `stats.json`),
}));
}
if (snapshot) {
config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
chunk: "vendor",
angular: true,
requireModules: [
"reflect-metadata",
"#angular/platform-browser",
"#angular/core",
"#angular/common",
"#angular/router",
"nativescript-angular/platform-static",
"nativescript-angular/router",
],
projectRoot,
webpackConfig: config,
snapshotInDocker,
skipSnapshotTools,
useLibs
}));
}
if (hmr) {
config.plugins.push(new webpack.HotModuleReplacementPlugin());
}
return config;
};
How can I figure out the fix?
Actually, this issue is related to version of "#angular-devkit/build-angular".
For me works!
After generating code sharing project:
Drop folders: 'hooks', 'node_modules', 'platforms'
Drop files: 'package-lock.json', 'webpack.config.js'
Change version of '#angular-devkit/build-angular' from current (~0.803.0) to ~0.7.0 ; Then run npm install
Then change '#angular-devkit/build-angular' version to current one (~0.803.0). Then run nmp install
Test: tns run ios --bundle
The same happened to me and When I try to edit webpack.config.js it works for me just replace the lines
new CopyWebpackPlugin([
{ from: { glob: "fonts/**" } },
{ from: { glob: "**/*.jpg" } },
{ from: { glob: "**/*.png" } },
], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
to be
new CopyWebpackPlugin({
patterns: [
{ from: "fonts/**", globOptions: { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] } },
{ from: "**/*.{jpg,png}", globOptions: { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] } },
]
}, { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
and do not forget to add fonts folder if you do not have one

Nativescript-Angular code sharing: How do I create platform specific modules?

Imagine I have OrderComponent and CustomerComponent that represent two screens.
In the web version you can create a new customer while in the order screen by launching the customer component inside a popup. So OrderComponent references CustomerComponent directly in the template. So I have to keep both in the same FeaturesModule for this to work.
On the other hand in the Nativescript mobile version, there is no such capability and so the two components/screens are completely independent, so I would like to put them in 2 separate modules: OrderModule, and CustomerModule. And lazy load them so the app launches faster.
In my real application of course it's not just 2 components but several dozens so the mobile app performance is a more pressing issue.
When I try to add a module file with the tns extension like this: order.module.tns.ts, without the corresponding web file, it seems as if the NativeScript bundler is not picking it up, I get the following error:
ERROR: C:\...\src\app\features\orders\orders.module.ts is missing from the TypeScript compilation. Please make sure it is in your tsconfig via the 'files' or 'include' property.
at AngularCompilerPlugin.getCompiledFile (C:\Users\...\node_modules\#ngtools\webpack\src\angular_compiler_plugin.js:753:23)
at plugin.done.then (C:\Users\...\node_modules\#ngtools\webpack\src\loader.js:41:31)
at process._tickCallback (internal/process/next_tick.js:68:7)
# ../$$_lazy_route_resource lazy namespace object ./features/measurement-units/measurement-units.module
# ../node_modules/#angular/core/fesm5/core.js
# ../node_modules/nativescript-angular/platform.js
# ./main.ns.ts
But according to the docs, all I have to do to make a nativescript specific component is add it with the tns extension. Is there another step to make this work for module files?? Help is appreciated
Update
Here is my tsconfig.tns.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "es2015",
"moduleResolution": "node",
"baseUrl": "./",
"paths": {
"~/*": [
"src/*"
],
"*": [
"./node_modules/tns-core-modules/*",
"./node_modules/*"
]
}
}
}
Update 2
My webpack.config.js:
const { join, relative, resolve, sep } = require("path");
const webpack = require("webpack");
const nsWebpack = require("nativescript-dev-webpack");
const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target");
const { nsReplaceBootstrap } = require("nativescript-dev-webpack/transformers/ns-replace-bootstrap");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const { AngularCompilerPlugin } = require("#ngtools/webpack");
module.exports = env => {
// Add your custom Activities, Services and other Android app components here.
const appComponents = [
"tns-core-modules/ui/frame",
"tns-core-modules/ui/frame/activity",
];
const platform = env && (env.android && "android" || env.ios && "ios");
if (!platform) {
throw new Error("You need to provide a target platform!");
}
const projectRoot = __dirname;
// Default destination inside platforms/<platform>/...
const dist = resolve(projectRoot, nsWebpack.getAppPath(platform, projectRoot));
const appResourcesPlatformDir = platform === "android" ? "Android" : "iOS";
const {
// The 'appPath' and 'appResourcesPath' values are fetched from
// the nsconfig.json configuration file
// when bundling with `tns run android|ios --bundle`.
appPath = "app",
appResourcesPath = "app/App_Resources",
// You can provide the following flags when running 'tns run android|ios'
aot, // --env.aot
snapshot, // --env.snapshot
uglify, // --env.uglify
report, // --env.report
sourceMap, // --env.sourceMap
hmr, // --env.hmr,
} = env;
const externals = (env.externals || []).map((e) => { // --env.externals
return new RegExp(e + ".*");
});
const appFullPath = resolve(projectRoot, appPath);
const appResourcesFullPath = resolve(projectRoot, appResourcesPath);
const entryModule = `${nsWebpack.getEntryModule(appFullPath)}.ts`;
const entryPath = `.${sep}${entryModule}`;
const ngCompilerPlugin = new AngularCompilerPlugin({
hostReplacementPaths: nsWebpack.getResolver([platform, "tns"]),
platformTransformers: aot ? [nsReplaceBootstrap(() => ngCompilerPlugin)] : null,
mainPath: resolve(appPath, entryModule),
tsConfigPath: join(__dirname, "tsconfig.tns.json"),
skipCodeGeneration: !aot,
sourceMap: !!sourceMap,
});
const config = {
mode: uglify ? "production" : "development",
context: appFullPath,
externals,
watchOptions: {
ignored: [
appResourcesFullPath,
// Don't watch hidden files
"**/.*",
]
},
target: nativescriptTarget,
entry: {
bundle: entryPath,
},
output: {
pathinfo: false,
path: dist,
libraryTarget: "commonjs2",
filename: "[name].js",
globalObject: "global",
},
resolve: {
extensions: [".ts", ".js", ".scss", ".css"],
// Resolve {N} system modules from tns-core-modules
modules: [
resolve(__dirname, "node_modules/tns-core-modules"),
resolve(__dirname, "node_modules"),
"node_modules/tns-core-modules",
"node_modules",
],
alias: {
'~': appFullPath
},
symlinks: true
},
resolveLoader: {
symlinks: false
},
node: {
// Disable node shims that conflict with NativeScript
"http": false,
"timers": false,
"setImmediate": false,
"fs": "empty",
"__dirname": false,
},
devtool: sourceMap ? "inline-source-map" : "none",
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
name: "vendor",
chunks: "all",
test: (module, chunks) => {
const moduleName = module.nameForCondition ? module.nameForCondition() : '';
return /[\\/]node_modules[\\/]/.test(moduleName) ||
appComponents.some(comp => comp === moduleName);
},
enforce: true,
},
}
},
minimize: !!uglify,
minimizer: [
new UglifyJsPlugin({
parallel: true,
cache: true,
uglifyOptions: {
output: {
comments: false,
},
compress: {
// The Android SBG has problems parsing the output
// when these options are enabled
'collapse_vars': platform !== "android",
sequences: platform !== "android",
}
}
})
],
},
module: {
rules: [
{
test: new RegExp(entryPath),
use: [
// Require all Android app components
platform === "android" && {
loader: "nativescript-dev-webpack/android-app-components-loader",
options: { modules: appComponents }
},
{
loader: "nativescript-dev-webpack/bundle-config-loader",
options: {
angular: true,
loadCss: !snapshot, // load the application css if in debug mode
}
},
].filter(loader => !!loader)
},
{ test: /\.html$|\.xml$/, use: "raw-loader" },
// tns-core-modules reads the app.css and its imports using css-loader
{
test: /[\/|\\]app\.css$/,
use: {
loader: "css-loader",
options: { minimize: false, url: false },
}
},
{
test: /[\/|\\]app\.scss$/,
use: [
{ loader: "css-loader", options: { minimize: false, url: false } },
"sass-loader"
]
},
// Angular components reference css files and their imports using raw-loader
{ test: /\.css$/, exclude: /[\/|\\]app\.css$/, use: "raw-loader" },
{ test: /\.scss$/, exclude: /[\/|\\]app\.scss$/, use: ["raw-loader", "resolve-url-loader", "sass-loader"] },
{
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
use: [
"nativescript-dev-webpack/moduleid-compat-loader",
"#ngtools/webpack",
]
},
// Mark files inside `#angular/core` as using SystemJS style dynamic imports.
// Removing this will cause deprecation warnings to appear.
{
test: /[\/\\]#angular[\/\\]core[\/\\].+\.js$/,
parser: { system: true },
},
],
},
plugins: [
// Define useful constants like TNS_WEBPACK
new webpack.DefinePlugin({
"global.TNS_WEBPACK": "true",
"process": undefined,
}),
// Remove all files from the out dir.
new CleanWebpackPlugin([`${dist}/**/*`]),
// Copy native app resources to out dir.
new CopyWebpackPlugin([
{
from: `${appResourcesFullPath}/${appResourcesPlatformDir}`,
to: `${dist}/App_Resources/${appResourcesPlatformDir}`,
context: projectRoot
},
]),
// Copy assets to out dir. Add your own globs as needed.
new CopyWebpackPlugin([
{ from: "fonts/**" },
{ from: "**/*.jpg" },
{ from: "**/*.png" },
], { ignore: [`${relative(appPath, appResourcesFullPath)}/**`] }),
// Generate a bundle starter script and activate it in package.json
new nsWebpack.GenerateBundleStarterPlugin([
"./vendor",
"./bundle",
]),
// For instructions on how to set up workers with webpack
// check out https://github.com/nativescript/worker-loader
new NativeScriptWorkerPlugin(),
ngCompilerPlugin,
// Does IPC communication with the {N} CLI to notify events when running in watch mode.
new nsWebpack.WatchStateLoggerPlugin(),
],
};
if (report) {
// Generate report files for bundles content
config.plugins.push(new BundleAnalyzerPlugin({
analyzerMode: "static",
openAnalyzer: false,
generateStatsFile: true,
reportFilename: resolve(projectRoot, "report", `report.html`),
statsFilename: resolve(projectRoot, "report", `stats.json`),
}));
}
if (snapshot) {
config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
chunk: "vendor",
angular: true,
requireModules: [
"reflect-metadata",
"#angular/platform-browser",
"#angular/core",
"#angular/common",
"#angular/router",
"nativescript-angular/platform-static",
"nativescript-angular/router",
],
projectRoot,
webpackConfig: config,
}));
}
if (hmr) {
config.plugins.push(new webpack.HotModuleReplacementPlugin());
}
return config;
};

Resources