Use webpack from 0 to build a multi-portal scaffolding, reusable navigation / bottom banner / sidebar, automatically change the configuration according to the page file, support ES6 / Less

Before know webpack very strong, but has not been studied in depth, this tutorial looked at from the beginning, starting from 0 and then set up scaffolding to develop a multi-portal, encountered many problems during the so determined to sort out the hope give us some help.

Multi-site using HTML necessity of webpack

If we receive such a mission, develop a simple official website, for example, only a dozen html page. The project is very simple, we do not need to use any large frame, but if you just write a few traditional html, js and css, is sure to encounter these problems:

  • Site navigation and the bottom of each page banner is common, how to reuse? If you no longer use, then the time will change with changes of n pages, would be too silly
  • How to force the user to empty the cache after the change? We can not require users to manually clear your browser cache so silly
  • I want to use ES6 js development, and how to resolve browser compatibility issues?
  • I want to use less css styles were developed, how to convert?

As can be seen, there is no automated tools packaged join, we are very difficult to solve these problems, so using webpack imperative.

To achieve the goal

See here, some students may be anxious, do not bullshit, I feel get to the bar, do not! Let's set goals! Whatever you do, they have to set goals, rather than where the operator where to dry, so there will not be a big upgrade, it is to overcome a variety of problems on the way towards the goal, we have progress, making this before scaffolding, I hope it is this

  • Html files can be packaged into a plurality of files and js, i.e. supports multiple inlet
  • File name should be put on hash values, resolve caching issues
  • Be able to reuse the site of the head of the navigation bar and bottom banner
  • Written styling through the use of less
  • To support the development ES6
  • To facilitate use them to increase the pages do not need to manually change the settings webpack entrance, hoping to automatic configuration based on file directory
  • Do not want to insert dynamically by js css styles, this will cause the page flicker, hope introduced directly into the html css address, as usual development as
  • You can see in real time the effect of development
  • possible to build compression code

Well, the goal set, start

Directory Structure

Do not worry, let stroked a stroke directory, do not worry writing code, a good catalog, let us clear thinking, my directory structure is as follows

+ config                    //环境变量配置文件,开发模式和生产模式使用不同的环境变量,比如接口地址,开发环境用的接口域名是http://a.com,生产环境使用的是http://b.com
    - dev.env.js            //本地开发变量   
    - prod.env.js           //生产环境变量
+ src                       
    + css                   //自己的less组件或者第三方css库
         + component        //自己组件的less
         + lib              //第三方的css库,比如bootstrap
    + html                  //html代码,主要是一些模板,如头部导航,底部通栏,侧边栏
         + tpl              //模板文件
    + img                   //图片文件
    + js                    //自己的js组件库或者第三方js库
         + mod              //自己的js组件放这里
         + lib              //第三方js库
    + page                  //页面文件
         + index            //这个根据自己情况设置,有的页面相关性强,可以放到一个文件夹下,比如一个user文件夹,可以放个人中心的所有页面
             - index.html   //每个页面都要有一个html
             - index.js     //每个页面都要有一个js,名称和html的名称保持一致
             - index.less   //每个页面都要有一个同名less文件
          + test
             - test.html
             - test.js
             - test.less    
             
+ webpack                   //webpack的配置文件
     - dev-server.js        //开发服务设置,可以通过localhost访问页面,页面的实时编译
     - webpack.common.js    //开发环境和生产环境通用配置
     - webpack.dev.js       //开发环境特有的配置
     - webpack.prod.js      //生产环境特有的配置

The first is the config directory, now I mainly put some environment variables, is the development and production environments are different variables, such as interface addresses, when we developed with the local api interface address, and packing time, to replace the production environment api address.

webpack directory contains webpack configuration file, which develop and produce common configuration into webpack.common.js, the development of a unique configuration into webpack.dev.js, the unique configuration into production in webpack.prod.js.

src develop our home directory, which placed our page directory page file, and may function differently than usual, I used every page of html, js files and less put together, some students may put all html into a directory, js into a directory, but there is such a problem, every time the page changes, we must look through the catalog, very inconvenient, we should put together this highly relevant documents, and extract js css various components or assemblies may be placed separately from the page.

github Address: HTTPS: //github.com/501351981 / ...

Multi-Entry Configuration

webpack support multi-entry, namely given multiple entry js files, you can output multiple js files, html how to do it? I hope that the development process is like this, I set the title in html, SEO and other information, write HTML content code, webpack the relevant js file is automatically inserted into the bottom of the html on the line, you can, which need to use html-webpack-plugin plugin , can be packaged by calling the html template file final html.

Installation html-webpack-plugin

npm install --save-dev html-webpack-plugin

Multi inlet arranged webpack.common.js

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports={

    entry:[
        index:'../src/page/index/index.js',
        test:'../src/page/test/test.js'
    ],
    
    output: {
        filename: '[name].[hash].js',   //输出名称后面跟哈希值,解决缓存问题
        path: path.resolve(__dirname,'../dist')
    },

    ....
    
    plugins: [
      new HtmlWebpackPlugin({
         filename: 'index.html',
         template: '../src/page/index/index.html',
         chunks: ['index'],
      })
      
      new HtmlWebpackPlugin({
         filename: 'test.html',
         template: '../src/page/test/test.html',
         chunks: ['test'],
      })
    ]
}

Setting such a problem, every time a new page, I'll add it here, too much trouble, in fact, we can read the js file in the src / page, automatically added to the inlet configuration; read / under src page All html files, automatically call the new HtmlWebpackPlugin be instantiated.

Read all the file names in the directory, we need to introduce glob, install

npm install --save-dev glob

The improved configuration

const glob = require('glob')
const CleanWebpackPlugin = require('clean-webpack-plugin');

//多入口js的配置,读取src/page下所有的js文件
function entries() {
    let jsDir = path.resolve(__dirname, '../src/page')
    let entryFiles = glob.sync(jsDir + '/**/*.js')
    let map = {};

    for (let i = 0; i < entryFiles.length; i++) {
        let filePath = entryFiles[i];
        let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'));
        map[filename] = filePath;
    }
    return map;
}

//读取多个html模板,进行插件实例化
function newHtmlWebpackPlugins(){
    let jsDir = path.resolve(__dirname, '../src/page')
    let htmls = glob.sync(jsDir + '/**/*.html')
    let plugins=[]

    for (let i = 0; i < htmls.length; i++) {
        let filePath = htmls[i];
        let filename_no_extension = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'));
        let filename=filename_no_extension.concat('.html')
       plugins.push(new HtmlWebpackPlugin({
           filename: filename,
           template: filePath,
           chunks: [filename_no_extension],
       }))
    }

    return plugins
}


module.exports={

    entry:entries(),
    
    output: {
        filename: '[name].[hash].js',
        path: path.resolve(__dirname,'../dist')
    },

    ....
    
    plugins: [
      ...newHtmlWebpackPlugins()
    ]
}

Well, now the new page does not need to change webpack configuration, and only need to re-run the npm run start to

There are head and the bottom of the multiplex

The head Navigation and bottom of each page banner we are all the same, and therefore needs to be introduced, then how to introduce another html html in it, which need to use raw-loader or html-withimg-loader

Installation raw-loader, raw-loader can load the contents of the original file (utf-8 format)

npm install --save-dev raw-loader
//目录结构

+ src                       
   
    + html                  
         + tpl              
             - navbar.html  //共用的头部导航  
             - footer.html  //共用的底部导航
    + page                  //页面文件
         + index            
             - index.html   
        
          + test
             - test.html

So we can reference and navigation bar at the bottom through the index.html

<!--引入通用的导航部分-->
<%=require('raw-loader!../../html/tpl/navbar.html')%>

<!--页面的正式内容在这里-->
<div id="app">
    <p>首页的内容在这里</p>
</div>

<!--引入通用的底部栏-->
<%=require('raw-loader!../../html/tpl/footer.html')%>

Initially I'm looking for solutions, I saw the article is recommended to use raw-loader, but found that there is such a problem that can not refer to the local navigation images, such as navigation cited a logo image, can not be found, because we when packing the picture will be processed to add back hash value, write directly to the image path does not work, then I switch to html-withimg-loader solved

Install html-withimg-loader, as the name implies, this plugin can be loaded html with pictures

npm install --save-dev html-withimg-loader
<!--引入通用的导航部分-->
<%=require('html-withimg-loader!../../html/tpl/navbar.html')%>

<!--页面的正式内容在这里-->
<div id="app">
    <p>首页的内容在这里</p>
</div>

<!--引入通用的底部栏-->
<%=require('html-withimg-loader!../../html/tpl/footer.html')%>

Incidentally, html referenced in the picture is the need to address written, need to require for the job, simply fill in the address of the picture is not enough

<img src="${require('../../img/react.png')}" width="50" height="50">

Support ES6 write js

I believe we now have learned ES6, but in view of the compatibility of the browser, not by arbitrary law requires plug-in support, we first installed

npm install --save-dev babel-loader babel-core babel-preset-env

Add webpack Configuration

webpack.common.js, we only js src directory conversion

{
    test: /\.js$/,
    use: {
        loader: 'babel-loader'
    },
    include: path.resolve(__dirname,'../src')
},

While adding a file in the project directory named .babelrc, the set of babel, support more than 1% share of the browser's most recent two versions

{
  "presets": [
    ["env",{
      "targets": {
        "browsers": ["> 1%", "last 2 versions"]
      }
    }]
  ],
}

babel just ES6 syntax into the syntax of ES5, such as the arrow function into function () {}, but for some ES6-specific features do not translate, such as new Map (), after packaging or new Map (), we still need install a plug-in to complete the conversion work.

npm install --save-dev babel-plugin-transform-runtime

Change the file .babelrc

{
  "presets": [
    ["env",{
      "targets": {
        "browsers": ["> 1%", "last 2 versions"]
      }
    }]
  ],
  "plugins": ["transform-runtime"]    //引入插件
}

You can now feel free to make use of the ES6

Use Less writing style

First install the relevant plug-ins or

npm install --save-dev less less-loader css-loader style-loader

webpack.common.js Configuration

{
    test: /\.css$/,
    use:["style-loader","css-loader","less-loader"]
},

In index.js file, so we can file the introduction of less

import './index.less'

After packing, running html page, index.js dynamically inserted into the css style html page, this will cause a problem, just the load is a style html, css styles are inserted after js another style, resulting in page glitters, experience is not good (technical but also the pursuit of the user experience ah, not only is the product manager of thing). There are two solutions to it, the first one is completed before the JS is not loaded, display a loading animation, to cover the whole page, and the second is to css file path packaged into html, do not add dynamically by js, I chosen the second option.

We need less files are packaged into a css file, you need to use plug-extract-text-webpack-plugin

npm install --save-dev extract-text-webpack-plugin

webpack.common.js

const ExtractTextPlugin = require("extract-text-webpack-plugin");

module.exports={
    rules: [
        {
            test: /\.less$/,
            use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: "css-loader!less-loader"
            })

       },
    ]
}

plugins: [
   new ExtractTextPlugin("[name].[hash:8].css"),
]

html after this package will be introduced css file like this


    <link href="index.5eb2501d.css" rel="stylesheet">

webpack Configuration

I'm actually in the process of starting from 0 built in, is to be webpack this configuration, the reason put the final did not want to influence the contents of the trunk, below we briefly explain my webpack configuration.

webpack official recommendation not to write duplicate configuration, namely the local environment and production into a common configuration file, and then merged by merge

webpack.dev.js

const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./webpack.common');

var OpenBrowserPlugin = require('open-browser-webpack-plugin');

const env=require("../config/dev.env")

module.exports=merge(common,{
    mode:"development",
    devtool: 'inline-source-map',
    plugins:[
        new webpack.DefinePlugin({
            'process.env': env
        }),
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new OpenBrowserPlugin({ url: 'http://localhost:5000' })
    ],
})

We can see that by webpack-merge plug-in, the common Configuration webpack.common.js and development merge

new webpack.DefinePlugin({
            'process.env': env
 }),

DefinePlugin defines global variables process.env

new OpenBrowserPlugin({ url: 'http://localhost:5000' })

This plug-in is after we allow for npm run start, automatically open the page HTTP: // localhost : 5000, avoid manually open each time.
webpack-dev-server provides us with a simple web server, and can be reloaded in real time, so that we can see the results in real-time development, web server configuration on, I put in dev-server.js

const webpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');

const config = require('./webpack.dev');
const options = {
    contentBase: './dist',
    hot: true,
    host: 'localhost',
};

webpackDevServer.addDevServerEntrypoints(config, options);
const compiler = webpack(config);
const server = new webpackDevServer(compiler, options);

server.listen(5000, 'localhost', () => {
    console.log('dev server listening on port 5000');
});

In package.json, we add two scripts

"scripts": {
  "start": "node webpack/dev-server.js",
  "build": "npx webpack --config webpack/webpack.prod.js",
},

So that we can enter two command line

npm run start: enter development mode

npm run build: Packaging production codes

Well, basically I do the introduction of this scaffolding is over, the real need to understand their own to try to see is one thing, doing it is another matter, others say it is more difficult to understand, and front-end The road is long, we will try it.

github Address: HTTPS: //github.com/501351981 / ...

The scaffolding is not perfect, but basic enough, I will do a few behind scaffolding, such as joint development vue multi-page or mobile terminal H5 development, we are interested can continue to focus.

Guess you like

Origin www.cnblogs.com/baimeishaoxia/p/11809296.html