關於 Vue webpack 模板的一些改造

綾丶宇發表於2019-03-04

最近在公司內部推 Vuejsvue-cli webpack 生成的專案無法滿足現有的需求,於是乎開始改造 vue-cli 初始化的專案, 主要解決專案多頁面和外部引入樣式檔案沒有 autoprefixer 的問題。

多頁面改造

vue webpack 模板預設是 SPA 專案,改成多頁面則需要把單入口變為多入口,生成多個html檔案。

專案結構

|—— src
  |—— assets
  |—— components      // 多個頁面間的公共元件
  |—— pages 
    |—— hello
      |—— hello.vue   // 頁面主vue檔案,和資料夾一致方便搜尋
      |—— index.html  // html模板檔案
      |—— main.js     // 入口檔案複製程式碼

pages 資料夾下每個頁面都新建一個資料夾,固定三個檔案 index.htmlmain.jspage.vue , 後續會有程式碼來識別產生多入口

構建程式碼修改

構建邏輯部分需要自定識別 pages 下的資料夾,生成多個 entry

首先,增加一個 page.js 初始化所有的頁面資訊

// page.js
var glob = require(`glob`);
var path = require(`path`);
var fs = require(`fs`);
var chalk = require(`chalk`);

var ENTRY = `main.js`;
var PAGE_FLODER = path.resolve(__dirname, `../src/pages/`);
var PAGES = PAGE_FLODER + `/**/` + ENTRY;
var TEMPLATE = `index.html`;

function initPages() {
    var pages = {};
    glob.sync(PAGES).forEach(function (entry) {
        var pageName = getPageName(entry);
        var templatePath = getTemplatePath(entry);
        if (!fs.existsSync(templatePath)) {
            console.log(chalk.yellow(pageName + `找不到模板檔案`));
            return;
        }

        pages[pageName] = {
            name: pageName,
            entry: entry,
            template: templatePath
        };
    });

    return pages;
}

function getPageName(filePath) {
    return filePath.substring(PAGE_FLODER.length + 1, filePath.indexOf(ENTRY) - 1);
}

function getTemplatePath(filePath) {
    var templatePath = filePath.substring(0, filePath.indexOf(ENTRY));
    templatePath += TEMPLATE;
    return templatePath;
}

module.exports = initPages();複製程式碼

然後 修改 config/index.js

module.exports = {
    pages: require(`./page`),   // 增加page的配置
    // ...
};複製程式碼

接下,utils.js 增加兩個函式用來生成多個 entryHtmlWebpackPlugin

// utils.js
//...
exports.getEntry = function () {
    var entry = {};
    Object.keys(config.pages).forEach(function (name) {
        entry[name] = config.pages[name].entry;
    });
    return entry;
}

exports.getHtmlPlugin = function () {
    var assetsSubDirectory = process.env.NODE_ENV === `production` ?
        config.build.assetsSubDirectory :
        config.dev.assetsSubDirectory;
    return Object.keys(config.pages).map(function (name) {
        return new HtmlWebpackPlugin ({
            template: config.pages[name].template,
            filename: name + `.html`,
            inject: true,
            chunks: [`vendor`, `manifest`, name],
            minify: env === `production` ? {
              removeComments: true,
              collapseWhitespace: true,
              removeAttributeQuotes: true
              // more options:
              // https://github.com/kangax/html-minifier#options-quick-reference
            } : undefined,
            // necessary to consistently work with multiple chunks via CommonsChunkPlugin
            chunksSortMode: env === `production` ? `dependency` : undefined
        })
    })
}複製程式碼

最後改動 webpack.base.conf.jswebpack.dev.conf.jswebpack.prod.conf.js

// webpack.base.conf.js
// ...
module.exports = {
    entry: utils.getEntry() // 多入口配置
    // ...
}複製程式碼
// webpack.dev.conf.js
// ...
module.exports = merge(baseWebpackConfig, {
    // ...
    plugins: [
        new webpack.DefinePlugin({
            `process.env`: config.dev.env
        }),
        // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin()
    ].concat(utils.getHtmlPlugin()),  // 加入生成的多頁面 HtmlWebpackPlugin
});複製程式碼
// webpack.prod.conf.js
//...
webpackConfig.plugins = webpackConfig.plugins.concat(utils.getHtmlPlugin()); // 加上這行程式碼
//...複製程式碼

ok,大功告成, 這樣一來就變為多頁面專案了(這樣一來每個頁面至少需要三個檔案,自己寫了一個atom外掛,新建頁面時自動生成相關檔案和基礎程式碼)。

js內引入css沒有 autoprefixer

.vue 檔案寫的樣式都會經過 postcss 處理,但是專案中重構和js需要分開工作,所以需要將css檔案獨立出去,再在入口檔案中引入,這是發現沒有樣式沒有進過 postcss 處理.

這裡需要在樣式載入時使用 postcss-loader 處理

npm install postcss-loader --save-dev複製程式碼
// utils.js
exports.cssLoaders = function (options) {
    // ...
    return {
        css: generateLoaders([`css`, `postcss`]),
        postcss: generateLoaders([`css`, `postcss`]),
        less: generateLoaders([`css`, `postcss`, `less`]),
        sass: generateLoaders([`css`, `postcss`, `sass?indentedSyntax`]),
        scss: generateLoaders([`css`, `postcss`, `sass`]),
        stylus: generateLoaders([`css`, `postcss`, `stylus`]),
        styl: generateLoaders([`css`, `postcss`, `stylus`])
    };
}複製程式碼
// webpack.base.conf.js
var postcssConfig = [
    require(`autoprefixer`)({
        browsers: [`last 5 versions`, `android >= 4.2`, `ios >= 7`]
    })
];

module.exports = {
    // ...
    postcss: postcssConfig, // 增加postcss配置
    vue: {
        loaders: utils.cssLoaders({
            sourceMap: useCssSourceMap
        }),
        postcss: postcssConfig
    }
}複製程式碼

最後

最近又發現 vue webpack 模板又升級到了 webpack 2.2 馬上準備入一波坑了。

相關文章