PatrickJS / PatrickJS-starter

MFE Starter

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use Bootstrap 4 and Sass (and jQuery)

alvipeo opened this issue · comments

commented

ok, I'm not a pro neither in webpack nor any of these new shiny 0.x.x version tech YET, so... But just in case someone would need it, here's how I got Bootstrap 4 (alpha now) + sass working:

  1. npm install bootstrap-loader --save
  2. npm install jquery --save
  3. npm install bootstrap@4.0.0-alpha.2 --save
  4. npm install css-loader node-sass resolve-url-loader sass-loader style-loader url-loader --save-dev
  5. Added autoprefixer to web.config.js (to use with postcss - optional):
    const autoprefixer = require('autoprefixer');

    postcss: [autoprefixer],  // this is inside module.exports object
  1. Add loaders to webpack.config.js:
        { test: /\.scss$/, loaders: ['style', 'css', 'postcss', 'sass'] },
        { test: /\.(woff2?|ttf|eot|svg)$/, loader: 'url?limit=10000' },
        // Bootstrap 4
        { test: /bootstrap\/dist\/js\/umd\//, loader: 'imports?jQuery=jquery' }

  1. Add jQuery plugin to webpack.config.js (to plugins array):
        new ProvidePlugin({
            jQuery: 'jquery',
            $: 'jquery',
            jquery: 'jquery'
        })
  1. Add to the end of vendor.ts:
    import 'jquery';
    import 'bootstrap-loader';
  1. Add some Bootstrap markup to your home.html to see that it works

Resulting webpack.config.js:

// @AngularClass

/*
 * Helper: root(), and rootDir() are defined at the bottom
 */
var path = require('path');
// Webpack Plugins
var ProvidePlugin = require('webpack/lib/ProvidePlugin');
var DefinePlugin = require('webpack/lib/DefinePlugin');
var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ENV = process.env.ENV = process.env.NODE_ENV = 'development';
const autoprefixer = require('autoprefixer');

var metadata = {
    title: 'IlgGallery UI',
    baseUrl: '/',
    host: '192.168.1.2',
    port: 3000,
    ENV: ENV
};
/*
 * Config
 */
module.exports = {
    // static data for index.html
    metadata: metadata,
    // for faster builds use 'eval'
    devtool: 'source-map',
    debug: true,

    entry: {
        'vendor': './src/vendor.ts',
        'main': './src/main.ts' // our angular app
    },

    // Config for our build files
    output: {
        path: root('dist'),
        filename: '[name].bundle.js',
        sourceMapFilename: '[name].map',
        chunkFilename: '[id].chunk.js'
    },

    resolve: {
        // ensure loader extensions match
        extensions: ['', '.ts', '.js', '.json', '.css', '.html']
    },

    module: {
        preLoaders: [{ test: /\.ts$/, loader: 'tslint-loader', exclude: [/node_modules/] }],
        loaders: [
            // Support for .ts files.
            {
                test: /\.ts$/,
                loader: 'ts-loader',
                query: {
                    'ignoreDiagnostics': [
                        2403, // 2403 -> Subsequent variable declarations
                        2300, // 2300 -> Duplicate identifier
                        2374, // 2374 -> Duplicate number index signature
                        2375  // 2375 -> Duplicate string index signature
                    ]
                },
                exclude: [/\.(spec|e2e)\.ts$/, /node_modules\/(?!(ng2-.+))/]
            },

            // Support for *.json files.
            { test: /\.json$/, loader: 'json-loader' },

            // Support for CSS as raw text
            { test: /\.css$/, loader: 'raw-loader' },

            // support for .html as raw text
            { test: /\.html$/, loader: 'raw-loader' },

            // if you add a loader include the resolve file extension above

            { test: /\.scss$/, loaders: ['style', 'css', 'postcss', 'sass'] },
            { test: /\.(woff2?|ttf|eot|svg)$/, loader: 'url?limit=10000' },
            // Bootstrap 4
            { test: /bootstrap\/dist\/js\/umd\//, loader: 'imports?jQuery=jquery' }
        ]
    },

    // sassResources: path.resolve(__dirname, "./node_modules/bootstrap/scss"),

    postcss: [autoprefixer],

    plugins: [
        new CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js', minChunks: Infinity }),
        // static assets
        new CopyWebpackPlugin([{ from: 'src/assets', to: 'assets' }]),
        // generating html
        new HtmlWebpackPlugin({ template: 'src/index.html', inject: false }),
        // replace
        new DefinePlugin({
            'process.env': {
                'ENV': JSON.stringify(metadata.ENV),
                'NODE_ENV': JSON.stringify(metadata.ENV)
            }
        }),
        new ProvidePlugin({
            jQuery: 'jquery',
            $: 'jquery',
            jquery: 'jquery'
        })
    ],

    // Other module loader config
    tslint: {
        emitErrors: false,
        failOnHint: false
    },
    // our Webpack Development Server config
    devServer: {
        port: metadata.port,
        host: metadata.host,
        historyApiFallback: true,
        watchOptions: { aggregateTimeout: 300, poll: 1000 }
    },
    // we need this due to problems with es6-shim
    node: { global: 'window', progress: false, crypto: 'empty', module: false, clearImmediate: false, setImmediate: false }
};

// Helper functions

function root(args) {
    args = Array.prototype.slice.call(arguments, 0);
    return path.join.apply(path, [__dirname].concat(args));
}

function rootNode(args) {
    args = Array.prototype.slice.call(arguments, 0);
    return root.apply(path, ['node_modules'].concat(args));
}

I haven't changed webpack.prod.config.js so authors could help us out here please.

Hey @alvipeo, thanks a lot for sharing how to do this.

I noticed something (and maybe is that I'm just tired) with a couple of the classes I'm trying to apply, namely btn-success-outline and pull-xs-right, these don't seem to get applied to the elements I am working with. Do you happen to have gone through this as well?

I figured it out, it is loading Bootstrap version 3, not 4 as I intended.

From https://github.com/shakacode/bootstrap-loader/

You need to have a .bootstraprc that explicitly uses version 4, like so:

https://github.com/shakacode/bootstrap-loader/blob/master/.bootstraprc-4-default

This fixed it for me.

I'm quite sure that I carefully replicated all above steps, and still the production build fails:

c:\path\to\angular2-webpack-starter\node_modules\webpack-md5-hash\plugin\webpack_md5_hash.js:27
var source = chunk.modules.sort(compareModules).map(getModuleSource).reduce(concatenateSource);
^

TypeError: Reduce of empty array with no initial value
at Array.reduce (native)
at Compilation. (C:\fastems\MMS5\MMS_NG\angular2-webpack-starter\node_modules\webpack-md5-hash\plugin\webpack_md5_hash.js:27:82)
at Compilation.applyPlugins (C:\fastems\MMS5\MMS_NG\angular2-webpack-starter\node_modules\webpack\node_modules\tapable\lib\Tapable.js:26:37)

Debug build is working fine, as well as production build without jQuery, SASS & bootstrap.

EDIT: that particular problem was due to missing empty line at the end of vendors.ts file

When following the above guidelines, im getting:

ERROR in Cannot find module 'babel/polyfill'
 @ ./~/bootstrap-loader/loader.js 1:0-44

Tried googling like hell, looking through issues etc, nothing.

@Znow I'm not using this setup, but boostrap 4 is written in ES6, so I'm guessing the babel is a dependency of the bootsrap-loader. You have it npm installed as a dev dependency?

What version of node are you using @Znow ? I think I upgraded my node version and that fixed it. (you could use something like nvm if you are able to so you avoid the risk of breaking something by upgrading your node)

@ackzell Just updated node to latest, now I get another error:

image

Along with this in Chrome DevTools:

image

@Znow I didn't encounter that, sorry. Maybe removing the node_modules folder and $ npm install again?

Cannot find module is a typescript error where you should provide type definitions for the module. you can also declare the module it as type any. I should probably add a note about this

when you see the error Cannot find module x you need to include the type definition. see https://github.com/AngularClass/angular2-webpack-starter/blob/master/src/custom_typings.d.ts

Referencing in #199, consolidating UI/style related issues.

So I set this up without postcss, but what is the proper way to pull in scss files into my components?

In my component:
@Component({ selector: 'about', templateUrl: 'app/components/about/about.html', styles: [require('./about.scss')], providers: [Mockable], directives: [MockableList, ROUTER_DIRECTIVES], pipes: [] })

In my webpack.config.js in loaders array:
{ test: /\.scss$/, loaders: ['style', 'css', 'sass'] },

I am getting an error

EXCEPTION: TypeError: s.replace is not a function

So I tried to change the loader to this:
{ test: /\.scss$/, loader: 'raw-loader!sass-loader' },

Which got rid of the error, but my css is rendered with encapsulation and looks like my component is not encapsulated:
body.test[_ngcontent-gpk-3] { background: red; } body.test[_ngcontent-gpk-3] h3[_ngcontent-gpk-3] { color: #FFF; } body.test[_ngcontent-gpk-3] a[_ngcontent-gpk-3] { color: #FFF; }

So what would be the best way to have a "global" scss stylesheet, and then use component scss stylesheets together? I think I have gotten the global part, by turning off viewEncapsulation on the root app, but then do I need to turn it on for every single component inside the app to get the styles to work properly?

I guess basically I am asking how to overwrite the css for the body tag from a component stylesheet.

@jgrannas - Not sure if this is what you're referring to, but I have it set up to use a global main.scss file located in a separate directory called /assets/scss. That main SCSS file is referenced in the main/top-level AppComponent. It can then import other SCSS files like _common.scss. Even though viewEncapsulation is turned off for the primary component I can still require SCSS files for specific components and it works fine.

Try using the following for the loaders in your webpack.config.js:
loaders: ['raw-loader', 'sass-loader']

See what I have and maybe it will help:

Using loaders: ['raw-loader', 'sass-loader'] instead of loaders: ['style', 'css', 'postcss', 'sass'] solved my problems using scss in the current webpack.

If you use style-loader, then you can't put your scss inside the Angular2 @component decorator. It has to go above/outside of it, the non-angular way.

I used loaders: ['raw-loader', 'sass-loader'] and I can put the scss in the @component decorator:

@Component({
  selector: 'app',
  directives: [ RouterActive ],
  styles: [ require('./app.scss') ],
  template: require('./app.html'),
  ...
})

This guide is a little bit outdated, can anyone update it ?

Can anyone update this?

Yesterday I was able to integrate Boostrap 4, Sass and jQuery using the informations on this "issue" on the "last" commit of the master branch. Maybe I can update the information on this issue or it's best to make a new one?

@lpalli Can you please share your info on this. e.g. do you use require('bootstrap-loader') or do you somehow reference in webpack.config?

@lpalli @kjartanvalur I'm also curious about this.

@kjartanvalur @lhammond - Not sure if you're asking how to load the styles within the Angular 2 Component decorator, in which case my solution won't help. Also not sure if this is how @lpalli did it or was what he referring to, but I was able to integrate jQuery, Bootstrap 4, and Sass without using the bootstrap-loader, instead using the sass-loader and raw-loader as dev dependencies installed with npm, since I was also using Sass for each component. I added the following to the config/webpack.common.js file, under module.exports[module][loaders]:

// File loader for supporting images, for example, in CSS files.
{
  test: /\.(jpg|png|gif)$/,
  loader: 'file'
},

// SCSS Loader
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass']
//loaders: ['raw-loader', 'sass-loader']
},

// Fonts
{
test: /\.(woff2?|ttf|eot|svg)$/,
loader: 'url?limit=10000'
},

// Bootstrap 4
{
test: /bootstrap\/dist\/js\/umd\//,
loader: 'imports?jQuery=jquery'
}

Then under module.exports[plugins] I added the following (I needed c3 and d3, but you could leave those out):

// Plugin: jQuery
new ProvidePlugin({
    jQuery: 'jquery',
    $: 'jquery',
    jquery: 'jquery',
    c3: 'c3',
    d3: 'd3',
    'Tether': 'tether',
    'window.Tether': 'tether'
}),

And then would reference SCSS files from the component (ie src/app/dashboard/dashboard.component.ts) like this:

declare var $: any;

require('./dashboard.scss');

@Component({
    selector: 'dashboard',
    providers: [
        Title
    ],
    templateUrl: './dashboard.html'
})

The bad thing about this is that you lose the benefits of Angular 2's ViewEncapsulation, which means I have to require() each SCSS file within the component at the top of the file instead of within the Component decorator (using ViewEncapsulation) as of Webpack 2. I'm okay with that, as I don't see the huge benefit yet, but am still looking at other solutions to keep things the "Angular way". I'm also biased toward Node.js and am used to just require()ing things. Global SCSS files (if you have one or two) can be resolved by adding it to the loader chain with require('!!style!css!sass!./example.scss'), for example, but that's a whole other issue.

If you're interested in a working reference, you can see the repo I'm working on with the changes here, or just my personal fork that gets updated a bit more frequently here. It uses the latest changes in angular2-webpack-starter with Webpack 2, no Angular Material, just Bootstrap and a pattern library that uses Bootstrap under the covers called PatternFly (optional). Just my preference because I personally dislike Angular Material. To try it out:

git clone git@github.com:hawtio/hawtio-ipaas.git
cd hawtio-ipaas
npm install
npm start

Hope this helps someone!

...aand actually the guide has been updated since I last checked, and instructions are working for me (including both global styles and referencing Sass within Angular's Component decorator, using ViewEncapsulation). So you can just install Bootstrap 4 with npm install bootstrap@4.0.0-alpha.4 and follow this guide: https://github.com/AngularClass/angular2-webpack-starter/wiki/How-to-include-SCSS-in-components

To install bootstrap 3.

npm install bootstrap-loader
npm install --save-dev bootstrap-sass
npm install --save-dev css-loader node-sass resolve-url-loader sass-loader style-loader url-loader

In src/vendor.browser.ts add the following line:
import 'bootstrap-loader';

In config/webpack.common.js add the following loaders:

{ test:/bootstrap-sass[\/\\]assets[\/\\]javascripts[\/\\]/, loader: 'imports?jQuery=jquery' },
{ test: /\.(woff2?|svg)$/, loader: 'url?limit=10000' },
{ test: /\.(ttf|eot)$/, loader: 'file' },
{ test: /\.scss$/, loaders: ['style', 'css', 'postcss', 'sass'] }

It works fine for me.

Hello, I follow the post https://github.com/AngularClass/angular2-webpack-starter/wiki/How-to-use-Bootstrap-4-and-Sass-(and-jQuery)

But I have one big problem :(

image

If, you have any solution ?

Thanks

I did anything I found (not only from here) but did not succeed in getting bootstrap integrated with webpack starter.
Where I am so far can be found at git@gitlab.com:hoffi_examples/angular2-spring-boot.git

still get:

ERROR in ./~/bootstrap-loader/lib/bootstrap.loader.js!./~/bootstrap-loader/no-op.js
Module not found: Error: Can't resolve 'style' in '/Users/hoffmd9/DBs/git/examples/angular2/angular2-spring-boot/angular2-spring-boot-frontend/node_modules/bootstrap-loader'
BREAKING CHANGE: It's no longer allowed to omit the '-loader' prefix when using loaders.
                 You need to specify 'style-loader' instead of 'style'.
 @ ./~/bootstrap-loader/lib/bootstrap.loader.js!./~/bootstrap-loader/no-op.js 1:21-1267
 @ ./~/bootstrap-loader/loader.js
 @ multi bootstrap-loader

and things are not bootstrap on html yet sigh

anybody?

Hello, I think you can try this :
if you have install "style"
uninstall "style" on your project and try this : npm install "style-loader" --save-dev

And, if is not working what is your version of webpack ?

no, already had "style-loader": "^0.13.1" in package.json and no "style" anywhere.

├─┬ assets-webpack-plugin@3.5.0
├─┬ copy-webpack-plugin@4.0.1
├─┬ extract-text-webpack-plugin@1.0.1
│ └─┬ webpack-sources@0.1.3
├─┬ html-webpack-plugin@2.24.1
├─┬ karma-webpack@1.8.0
├── script-ext-html-webpack-plugin@1.3.4
├── v8-lazy-parse-webpack-plugin@0.3.0
├─┬ UNMET PEER DEPENDENCY webpack@2.1.0-beta.27
├─┬ webpack-dev-middleware@1.9.0
├─┬ webpack-dev-server@2.1.0-beta.11
├─┬ webpack-md5-hash@0.0.5
├─┬ webpack-merge@1.0.2

What I did to make it work (Bootstrap3):

npm install --save-dev bootstrap-sass

On the webpack.common.js I've added the following loaders:

{test:/bootstrap-sass[\/\\]assets[\/\\]javascripts[\/\\]/, loader: 'imports?jQuery=jquery' },
{test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000" },
{test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" }

and on the end I've put on the styles.scss:

$bootstrap-sass-asset-helper: true;
@import "~bootstrap-sass/assets/stylesheets/bootstrap";

For the JS components I've used the ng2-bootstrap.

This is for someone who is looking for VUE.JS 2 and Bootstrap 4 solution:
Stack overflow: http://stackoverflow.com/a/43383449/1292050
Git setup https://github.com/syed-haroon/vue-js-2-basic-setup

I also encourage you to take look at this URL for more sophisticate work setup https://github.com/prograhammer/example-vue-project