NativeScript / nativescript-cli

Command-line interface for building NativeScript apps
https://www.npmjs.com/package/nativescript
Apache License 2.0
1.04k stars 196 forks source link

--bundle option ignores app.scss file #3499

Closed RadouaneRoufid closed 6 years ago

RadouaneRoufid commented 6 years ago

Tell us about the problem

Applying a --bundle option makes the application lose its css. Everything is ok when the command is run without --bundle.

Local environment

Project data

app.component.ts

@Component({
    moduleId: module.id,
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss'] // I tried to delete this line but in vain
})
export class AppComponent implements OnInit, OnDestroy 

app.android.scss

@import './app-variables'; // I also tried '~/app-variables'
@import '~nativescript-theme-core/scss/index';
@import '~nativescript-theme-core/scss/platforms/index.android';

@import './app-common';

package.json

"dependencies": {
    "@angular/animations": "~5.2.1",
    "@angular/common": "^5.2.1",
    "@angular/compiler": "^5.2.1",
    "@angular/core": "^5.2.1",
    "@angular/forms": "^5.2.1",
    "@angular/http": "^5.2.1",
    "@angular/platform-browser": "^5.1.0",
    "@angular/platform-browser-dynamic": "^5.2.1",
    "@angular/router": "^5.2.1",
    "@ngrx/effects": "^4.1.1",
    "@ngrx/router-store": "^4.1.1",
    "@ngrx/store": "^4.1.1",
    "@ngrx/store-devtools": "^4.1.1",
    "@ngx-progressbar/core": "^3.0.1",
    "@ngx-progressbar/http-client": "^3.0.1",
    "@ngx-translate/core": "^6.0.1",
    "@ngx-translate/http-loader": "0.0.3",
    "arrive": "^2.3.1",
    "bootstrap": "4.0.0-alpha.6",
    "bootstrap-datepicker": "1.6.4",
    "bootstrap-social": "^5.1.1",
    "core-js": "^2.5.2",
    "font-awesome": "4.7.0",
    "fs": "0.0.1-security",
    "hammerjs": "^2.0.8",
    "i": "^0.3.6",
    "lodash": "^4.17.4",
    "materialize-css": "0.100.2",
    "nativescript-angular": "^5.2.0",
    "nativescript-background-http": "^3.2.0",
    "nativescript-bottom-navigation": "^1.1.2",
    "nativescript-bottombar": "^3.0.8",
    "nativescript-cardview": "^2.0.5",
    "nativescript-checkbox": "^3.0.3",
    "nativescript-floatingactionbutton": "^4.1.3",
    "nativescript-fresco": "^3.0.2",
    "nativescript-google-maps-sdk": "^2.5.0",
    "nativescript-imagepicker": "^5.0.0",
    "nativescript-localstorage": "^1.1.5",
    "nativescript-mediafilepicker": "^1.0.5",
    "nativescript-modal-datetimepicker": "^1.1.0",
    "nativescript-ng-shadow": "^2.1.0",
    "nativescript-oauth": "^2.0.1",
    "nativescript-phone": "^1.3.1",
    "nativescript-photoviewer": "^1.4.0",
    "nativescript-pro-ui": "^3.4.0-2018-1-9-3",
    "nativescript-snackbar": "^2.0.0",
    "nativescript-theme-core": "~1.0.2",
    "ng2-validation": "^4.2.0",
    "ngrx-store-freeze": "^0.1.9",
    "ngx-pagination": "^3.0.3",
    "npm": "^4.2.0",
    "osenv": "^0.1.4",
    "path": "^0.12.7",
    "reflect-metadata": "^0.1.12",
    "rxjs": "^5.5.5",
    "tether": "^1.4.3",
    "tns-core-modules": "^3.4.1",
    "url": "^0.11.0",
    "velocity-animate": "^1.5.1",
    "zone.js": "0.8.5"
  },
  "devDependencies": {
    "@angular/compiler-cli": "^5.2.1",
    "@ngtools/webpack": "~1.9.4",
    "@types/googlemaps": "^3.30.8",
    "@types/jasmine": "^2.8.5",
    "babel-traverse": "6.25.0",
    "babel-types": "6.25.0",
    "babylon": "6.17.4",
    "copy-webpack-plugin": "~4.3.0",
    "cross-env": "^5.1.3",
    "css-loader": "~0.28.7",
    "del": "^2.2.2",
    "extract-text-webpack-plugin": "~3.0.2",
    "gulp": "^4.0.0",
    "gulp-debug": "^3.1.0",
    "gulp-exec": "^3.0.1",
    "gulp-rename": "^1.2.2",
    "gulp-spawn": "^0.4.0",
    "gulp-string-replace": "^0.4.0",
    "lazy": "1.0.11",
    "mkdirp": "^0.5.1",
    "nativescript-css-loader": "~0.26.1",
    "nativescript-dev-android-snapshot": "^0.*.*",
    "nativescript-dev-sass": "^1.4.0",
    "nativescript-dev-typescript": "~0.6.0",
    "nativescript-dev-webpack": "^0.9.2",
    "nativescript-worker-loader": "~0.8.1",
    "raw-loader": "~0.5.1",
    "resolve-url-loader": "~2.2.1",
    "run-sequence": "^2.2.1",
    "sass-loader": "~6.0.6",
    "tns-platform-declarations": "^3.4.1",
    "typescript": "^2.4.0",
    "typescript-register": "^1.1.0",
    "uglifyjs-webpack-plugin": "~1.1.6",
    "webpack": "~3.10.0",
    "webpack-bundle-analyzer": "^2.9.1",
    "webpack-sources": "~1.1.0"
  }

const webpack = require("webpack"); const nsWebpack = require("nativescript-dev-webpack"); const nativescriptTarget = require("nativescript-dev-webpack/nativescript-target"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const ExtractTextPlugin = require("extract-text-webpack-plugin"); const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); const { NativeScriptWorkerPlugin } = require("nativescript-worker-loader/NativeScriptWorkerPlugin"); const UglifyJsPlugin = require("uglifyjs-webpack-plugin");

module.exports = env => { const platform = env && (env.android && "android" || env.ios && "ios"); if (!platform) { throw new Error("You need to provide a target platform!"); } const platforms = ["ios", "android"]; const { snapshot, uglify, report, aot } = env; const ngToolsWebpackOptions = { tsConfigPath: "tsconfig.json" };

const config = {
    context: resolve("./app"),
    target: nativescriptTarget,
    entry: {
        bundle: aot ? "./main.aot.ts" : "./main.ts",
        vendor: "./vendor",
    },
    output: {
        pathinfo: true,
        // Default destination inside platforms/<platform>/...
        path: resolve(nsWebpack.getAppPath(platform)),
        libraryTarget: "commonjs2",
        filename: "[name].js",
    },
    resolve: {
        extensions: [".ts", ".js", ".scss", ".css"],
        // Resolve {N} system modules from tns-core-modules
        modules: [
            "node_modules/tns-core-modules",
            "node_modules",
        ],
        alias: {
            '~': resolve("./app")
        },
        // don't resolve symlinks to symlinked modules
        symlinks: false
    },
    resolveLoader: {
        // don't resolve symlinks to symlinked loaders
        symlinks: false
    },
    node: {
        // Disable node shims that conflict with NativeScript
        "http": false,
        "timers": false,
        "setImmediate": false,
        "fs": "empty",
    },
    module: {
        rules: [
            { 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"] },

            // Compile TypeScript files with ahead-of-time compiler.
            { test: /.ts$/, use: [
                "nativescript-dev-webpack/moduleid-compat-loader",
                { loader: "@ngtools/webpack", options: ngToolsWebpackOptions },
            ]},
        ],
    },
    plugins: [
        // Vendor libs go to the vendor.js chunk
        new webpack.optimize.CommonsChunkPlugin({
            name: ["vendor"],
        }),
        // Define useful constants like TNS_WEBPACK
        new webpack.DefinePlugin({
            "global.TNS_WEBPACK": "true",
        }),
        // Copy assets to out dir. Add your own globs as needed.
        new CopyWebpackPlugin([
            { from: "App_Resources/**" },
            { from: "fonts/**" },
            { from: "**/*.jpg" },
            { from: "**/*.png" },
            { from: "**/*.xml" },
        ]),
        // Generate a bundle starter script and activate it in package.json
        new nsWebpack.GenerateBundleStarterPlugin([
            "./vendor",
            "./bundle",
        ]),
        // Support for web workers since v3.2
        new NativeScriptWorkerPlugin(),
        // AngularCompilerPlugin with augmented NativeScript filesystem to handle platform specific resource resolution.
        new nsWebpack.NativeScriptAngularCompilerPlugin(
            Object.assign({
                entryModule: resolve(__dirname, "app/native.module#AppModule"),
                skipCodeGeneration: !aot,
                platformOptions: {
                    platform,
                    platforms,
                    // ignore: ["App_Resources"]
                },
            }, ngToolsWebpackOptions)
        ),
        // 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: join(__dirname, "report", `report.html`),
        statsFilename: join(__dirname, "report", `stats.json`),
    }));
}
if (snapshot) {
    config.plugins.push(new nsWebpack.NativeScriptSnapshotPlugin({
        chunk: "vendor",
        projectRoot: __dirname,
        webpackConfig: config,
        targetArchs: ["arm", "arm64", "ia32"],
        tnsJavaClassesOptions: { packages: ["tns-core-modules" ] },
        useLibs: false
    }));
}
if (uglify) {
    config.plugins.push(new webpack.LoaderOptionsPlugin({ minimize: true }));

    // Work around an Android issue by setting compress = false
    const compress = platform !== "android";
    config.plugins.push(new UglifyJsPlugin({
        uglifyOptions: {
            mangle: { reserved: nsWebpack.uglifyMangleExcludes },
            compress,
        }
    }));
}
return config;

};



Command executed : tns run android --bundle --device avd27
RadouaneRoufid commented 6 years ago

I had to do this as a possible workaround :

webpack.config.js

Declaring the main sheet

let mainSheet;
module.exports = env => {
    const platform = env && (env.android && "android" || env.ios && "ios");
    if (!platform) {
        throw new Error("You need to provide a target platform!");
    }
    const platforms = ["ios", "android"];
    const { snapshot, uglify, report, aot } = env;
    const ngToolsWebpackOptions = { tsConfigPath: "tsconfig.json" };

    mainSheet = `app.${platform}.css`;

    const config = {
        context: resolve("./app"),
        target: nativescriptTarget,
        entry: {
            bundle: aot ? "./main.aot.ts" : "./main.ts",
            vendor: "./vendor",
            [mainSheet]: `./${mainSheet}`,
        },
...

nativescript-dev-sass/lib/before-prepare.js

I had to modify this file, to allow scss file to be compiled when --bundle option is active.

var converter = require('./converter');

module.exports = function ($logger, $projectData, $usbLiveSyncService) {
    var liveSync = $usbLiveSyncService.isInitialized;
    var bundle = $projectData.$options.bundle;
    if (liveSync) {
        $logger.warn("Hook skipped because either bundling or livesync is in progress.")
        return;
    }

    return converter.convert($logger, $projectData.projectDir, $projectData.appDirectoryPath);
}

Style is now picked and applied.

NickIliev commented 6 years ago

@RadouaneRoufid - thank you for reporting this issue and providing a solution.

There were some issues related to SCSS and they are now being resolved in next branch. I have tested your scenario (demo app with SCSS and Angular here) with next modules, runtime and Webpack and everything works as expected. All of these changes will be included in the upcoming official release.

RadouaneRoufid commented 6 years ago

--env.snapshot causes the same issue.