33

Build a Website with Modern Tooling and No Frameworks

 5 years ago
source link: https://www.tuicool.com/articles/hit/YbUBNzE
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Setting up

To create the directory structure and all the necessary files copy the following to your terminal (Windows users, I’m not sure if the commands mkdir and touch will work for you. If not, you will have to create the directories and files one by one.)

mkdir -p vanilla-website/{public/assets/{images,scripts,styles},src/{scripts,styles}}
cd vanilla-website
yarn init -y
touch .babelrc postcss.config.js webpack.config.js public/index.html src/{scripts/{main.js,utils.js},styles/{main.scss,reset.scss}}

You should end up with the following project structure

├── .babelrc
├── package.json
├── postcss.config.js
├── /public
|  ├── /assets
|  |  ├── /images
|  |  ├── /scripts
|  |  └── /styles
|  └── index.html
├── /src
|  ├── /scripts
|  |  ├── main.js
|  |  └── utils.js
|  └── /styles
|     ├── main.scss
|     └── reset.scss
└── webpack.config.js
  • /public  — holds the website
  • /src  — holds the source files

Still in the root of the project, copy the following to your terminal to install the needed dependencies

yarn add -D @babel/core babel-loader @babel/preset-env cross-env css-loader cssnano file-loader live-server mini-css-extract-plugin node-sass npm-run-all postcss-loader postcss-preset-env sass-loader webpack webpack-cli
  • @babel/core, babel-loader, @babel/preset-env  — Transpile our ES6+ JavaScript to ES5, or whatever browsers we decide to support
  • cross-env  — Make Windows work with environment variables in CLI
  • css-loader, cssnano, mini-css-extract-plugin, node-sass, postcss-loader, postcss-preset-env, sass-loader  — Process our Sass, including autoprefixing, minification and extracting the CSS to a separate file
  • file-loader  — Handles images in our CSS
  • live-server  — Development server with auto-reloading capabilities when files change
  • npm-run-all  — Run multiple npm-scripts in parallel or sequential
  • webpack, webpack-cli  — Module bundler, the glue that puts everything together

Now you can open the project in your favorite editor (mine is VS Code) and bring up package.json . Copy the following scripts

"scripts": {
  "dev:assets": "webpack --watch",
  "dev:start": "live-server --open=./public/ --host=localhost --watch=./public/",
  "dev": "npm-run-all -p dev:*",
  "build": "cross-env NODE_ENV=production webpack"
},
  • dev:assets  — Running Webpack in watch mode will watch for changes to files in our /src directory and recompile everything. Webpack will place the compiled files under the /public directory
  • dev:start  — Start our development server, launch the browser to the /public directory and watch for changes under the /public directory. Website will open to http://localhost:8080/public
  • dev  — Run in parallel all of the scripts that start with dev: . Basically it will run dev:assets and dev:start giving us a nice development environment with live reload
  • build  — Run Webpack in production mode, optimizing CSS and JavaScript files. The outputted files will replace the CSS/JS development files under the /public directory, then you can take everything under this directory and deploy it to your production server

Configuration

Open .babelrc and copy the following

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "browsers": ["> 1%"]
        }
      }
    ]
  ]
}

Here we are making use of @babel/preset-env and instructing Babel to transpile our JavaScript code to support browsers that are used in more than 1% of the global market browser share. You can modify the target browsers according to your needs by using supported queries .

Here is the full list of the browsers with our current configuration: http://browserl.ist/?q=%3E+1%25

Open postcss.config.js and copy the following

const postcssPresetEnv = require('postcss-preset-env');
if (process.env.NODE_ENV === 'production') {
  module.exports = {
    plugins: [
      postcssPresetEnv({
        browsers: ['> 1%']
      }),
      require('cssnano')
    ]
  };
return;
}
module.exports = {};

We instruct PostCSS to autoprefix and minimize our CSS when in production mode, otherwise don’t do anything. Here we also use the same browser list as in Babel configuration. The same rules apply.

Remember in our build script we set NODE_ENV to production ? Well, we read that environment variable with process.env.NODE_ENV , and that’s how we know we are running in production mode.

It is time to configure Webpack, open webpack.config.js and copy the following

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
  // Tells Webpack which built-in optimizations to use
  // In 'production' mode, Webpack will minify and uglify our JS code
  // If you leave this out, Webpack will default to 'production'
  mode: devMode ? 'development' : 'production',
// Webpack needs to know where to start the bundling process,
  // so we define the main JS and Sass files, both under
  // the './src' directory
  entry: ['./src/scripts/main.js', './src/styles/main.scss'],
// This is where we define the path where Webpack will place
  // the bundled JS file
  output: {
    path: path.resolve(__dirname, 'public'),
// Specify the base path for all the assets within your
    // application. This is relative to the output path, so in
    // our case it will be ./public/assets
    publicPath: '/assets',
// The name of the output bundle. Path is also relative
    // to the output path
    filename: 'assets/scripts/bundle.js'
  },
  module: {
    // Array of rules that tells Webpack how the modules (output)
    // will be created
    rules: [
      {
        // Look for JavaScript files and apply the babel-loader
        // excluding the './node_modules' directory. It uses the
        // configuration in `.babelrc`
        test: /\.(js)$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      },
      {
        // Look for Sass files and process them according to the
        // rules specified in the different loaders
        test: /\.(sa|sc)ss$/,
// Use the following loaders from right-to-left, so it will
        // use sass-loader first and ending with MiniCssExtractPlugin
        use: [
          {
            // Extracts the CSS into a separate file and uses the
            // defined configurations in the 'plugins' section
            loader: MiniCssExtractPlugin.loader
          },
          {
            // Interprets CSS
            loader: 'css-loader',
            options: {
              importLoaders: 2
            }
          },
          {
            // Use PostCSS to minify and autoprefix. This loader
            // uses the configuration in `postcss.config.js`
            loader: 'postcss-loader'
          },
          {
            // Adds support for Sass files, if using Less, then
            // use the less-loader
            loader: 'sass-loader'
          }
        ]
      },
      {
        // Adds support to load images in your CSS rules. It looks
        // for .png, .jpg, .jpeg and .gif
        test: /\.(png|jpe?g|gif)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              // The image will be named with the original name and
              // extension
              name: '[name].[ext]',
// Indicates where the images are stored and will use
              // this path when generating the CSS files.
              // Example, in main.scss I have
              // url('../../public/assets/images/venice-italy.jpg')
              // and when generating the CSS file, it will be
              // outputted as url(../images/venice-italy.jpg), which
              // is relative to /styles/main.css
              publicPath: '../images',
// When this option is 'true', the loader will emit
              // the image to output.path
              emitFile: false
            }
          }
        ]
      }
    ]
  },
  plugins: [
    // Configuration options for MiniCssExtractPlugin. Here I'm only
    // indicating what the CSS outputted file name should be and
    // the location
    new MiniCssExtractPlugin({
      filename: 'assets/styles/main.css'
    })
  ]
};

Refer to the comments in the code to understand the configuration.

Coding the site

I will not be explaining everything from here on, since the focus of this tutorial is mainly to show how to set-up your environment for development.

Open ./public/index.html and copy the following

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>No Framework Website</title>
<link rel="stylesheet" href="./assets/styles/main.css">
</head>
<body>
<div class="wrapper">
<header>
<h1>No Framework Website</h1>
</header>
<main>
<h2>This site rocks </h2>
<div class="bacon">
<img src="./assets/images/oval.svg" alt="loading">
</div>
</main>
<footer>
<p>Made with :heart: by <a href="https://twitter.com/_esausilva" target="_blank">Esau Silva</a></p>
</footer>
</div>
<script src="./assets/scripts/bundle.js"></script>
</body>
</html>

Two things to notice here: the path to our stylesheet and our JavaScript file (in bold). This is exactly where Webpack is going to place our processed files.

Open ./src/styles/reset.scss and copy the following

html {
  height: 100%;
  box-sizing: border-box;
  font-size: 100%;
}
*,*:before,*:after { box-sizing: inherit; }
body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow-x: hidden;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial,
    sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
  color: #3b3b3b;
}
h1,h2,h3,h4,h5 {
  margin: 6px;
  padding: 0;
}

Open ./src/styles/main.scss and copy the following

@import 'reset.scss';
.wrapper {
min-height: 100vh;
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-template-rows: auto 1fr auto;
line-height: 23px;
& > * { grid-column: 2 / -2; }
  header {
    grid-column: 1 / -1;
    background: #fdbc9a url('../../public/assets/images/venice-italy.jpg') no-repeat center;
    background-size: cover;
    height: 500px;
    margin-bottom: 20px;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #fff;
    text-align: center;
h1 {
      font-size: 3.5em;
      text-shadow: -2px -2px 3px rgb(163, 162, 162);
    }
  }
  footer {
    height: 50px;
    display: flex;
    justify-content: flex-end;
  }
}
.bacon > img {
  width: 75px;
  display: block;
  margin: auto;
}

Open ./src/scripts/utils.js and copy the following

export const GetBacon = () => {
  const body = fetch('https://baconipsum.com/api/?type=all-meat&paras=3').then( res => res.json() );
  return body;
};

Fetches the Bacon Ipsum API and brings back 3 paragraphs.

Open ./src/scripts/main.js and copy the following

import { GetBacon } from './utils';
const baconEl = document.querySelector('.bacon');
GetBacon()
  .then(res => {
    const markup = res.reduce((acc, val) => (acc += `<p>${val}</p>`), '');
    baconEl.innerHTML = markup;
  }).catch(err => (baconEl.innerHTML = err));

Nothing complicated here; we’re just creating three dummy paragraphs and injecting them into the website.

The whole point is to show you can write modern JavaScript, including ES Modules, which will be processed through Webpack and transpiled to JavsScript that browsers can understand.

Finally, download these two images, image1 and image2 , and place them under  ./public/assets/images directory.

Now with everything done, open your terminal to the root of the project and type the following for development

yarn dev

Watch the browser live reload as you make changes to your source files. Type the following for production

yarn build

Take the ./public directory and deploy it to your server!!

You can get the full code on the Github repository .

Conclusion

You made it to the end. Congratulations :tada:. Now you have the tools to start creating sites with modern JavaScript and Sass. From here, it will be easy to extend Webpack if you want to support more things.

You could even combine Webpack and a templating language to create more robust websites, like Nunjucks or Handlebars .

Thank you for reading and I hope you enjoyed it. If you have any questions, suggestions or corrections let me know in the comments below. Don’t forget to give this article a share and you can follow me on Twitter , GitHub , Medium , LinkedIn .


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK