vue 로 다 중 페이지 응용 예시 코드 구축

19502 단어 vue다 중 페이지
최근 에 vue 를 사용 하여 뭔 가 를 만 드 는 것 을 연구 해 왔 지만 모두 SPA 의 단일 페이지 응용 이지 만 실제 업무 에서 단일 페이지 가 반드시 업무 수요 에 부합 되 지 않 기 때문에 이 편 은 여러 페이지 의 Vue 응용 을 어떻게 개발 하 는 지,그리고 이 과정 에서 발생 할 수 있 는 문 제 를 말씀 드 리 겠 습 니 다.
이것 은 제 가 GitHub 에 놓 은 프로젝트 입 니 다.그 안에 전체 프로필 이 있 습 니 다.참고 할 수 있 습 니 다multiple-vue-page
준비 작업
로 컬 vue-cli 로 항목 을 새로 만 듭 니 다.이 단계 vue 홈 페이지 에 있 습 니 다.더 이상 말 하지 않 겠 습 니 다.
npm install 명령 을 실행 하기 전에 package.json 에 의존 도 를 추가 하고 나중에 사용 할 곳 이 있 습 니 다.

웹 팩 설정 수정
제 프로젝트 목록 을 보 여 드릴 게 요.

├── README.md
├── build
│  ├── build.js
│  ├── check-versions.js
│  ├── dev-client.js
│  ├── dev-server.js
│  ├── utils.js
│  ├── vue-loader.conf.js
│  ├── webpack.base.conf.js
│  ├── webpack.dev.conf.js
│  └── webpack.prod.conf.js
├── config
│  ├── dev.env.js
│  ├── index.js
│  └── prod.env.js
├── package.json
├── src
│  ├── assets
│  │  └── logo.png
│  ├── components
│  │  ├── Hello.vue
│  │  └── cell.vue
│  └── pages
│    ├── cell
│    │  ├── cell.html
│    │  ├── cell.js
│    │  └── cell.vue
│    └── index
│      ├── index.html
│      ├── index.js
│      ├── index.vue
│      └── router
│        └── index.js
└── static
이 단계 에서 우리 가 변경 해 야 할 파일 은 모두 build 파일 아래 에 있 습 니 다.각각:
  • utils.js
  • webpack.base.conf.js
  • webpack.dev.conf.js
  • webpack.prod.conf.js
  • 나 는 순서대로 완전한 파일 내용 을 놓 고 수정 하거나 추가 한 위치 에 주석 부호 로 표시 할 것 이다.
    utils.js 파일
    
    // utils.js  
    
    var path = require('path')
    var config = require('../config')
    var ExtractTextPlugin = require('extract-text-webpack-plugin')
    
    exports.assetsPath = function (_path) {
      var assetsSubDirectory = process.env.NODE_ENV === 'production' ?
        config.build.assetsSubDirectory :
        config.dev.assetsSubDirectory
      return path.posix.join(assetsSubDirectory, _path)
    }
    
    exports.cssLoaders = function (options) {
      options = options || {}
    
      var cssLoader = {
        loader: 'css-loader',
        options: {
          minimize: process.env.NODE_ENV === 'production',
          sourceMap: options.sourceMap
        }
      }
    
      // generate loader string to be used with extract text plugin
      function generateLoaders(loader, loaderOptions) {
        var loaders = [cssLoader]
        if (loader) {
          loaders.push({
            loader: loader + '-loader',
            options: Object.assign({}, loaderOptions, {
              sourceMap: options.sourceMap
            })
          })
        }
    
        // Extract CSS when that option is specified
        // (which is the case during production build)
        if (options.extract) {
          return ExtractTextPlugin.extract({
            use: loaders,
            fallback: 'vue-style-loader'
          })
        } else {
          return ['vue-style-loader'].concat(loaders)
        }
      }
    
      // https://vue-loader.vuejs.org/en/configurations/extract-css.html
      return {
        css: generateLoaders(),
        postcss: generateLoaders(),
        less: generateLoaders('less'),
        sass: generateLoaders('sass', { indentedSyntax: true }),
        scss: generateLoaders('sass'),
        stylus: generateLoaders('stylus'),
        styl: generateLoaders('stylus')
      }
    }
    
    // Generate loaders for standalone style files (outside of .vue)
    exports.styleLoaders = function (options) {
      var output = []
      var loaders = exports.cssLoaders(options)
      for (var extension in loaders) {
        var loader = loaders[extension]
        output.push({
          test: new RegExp('\\.' + extension + '$'),
          use: loader
        })
      }
      return output
    }
    
    /*          ----------------------------    */
    
    // glob webpack             ,         *   ,   lib/*.js    lib       js      
    var glob = require('glob')
    //     
    var HtmlWebpackPlugin = require('html-webpack-plugin')
    //          ,       ,   src     pages   
    var PAGE_PATH = path.resolve(__dirname, '../src/pages')
    //       merge  
    var merge = require('webpack-merge')
    
    
    //     
    //   glob    pages              js    ,       
    //          
    exports.entries = function () {
      var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')
      var map = {}
      entryFiles.forEach((filePath) => {
        var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
        map[filename] = filePath
      })
      return map
    }
    
    //       
    //              ,  pages        html    ,       
    exports.htmlPlugin = function () {
      let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
      let arr = []
      entryHtml.forEach((filePath) => {
        let filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.'))
        let conf = {
          //     
          template: filePath,
          //     
          filename: filename + '.html',
          //           js  ,                  js  
          chunks: ['manifest', 'vendor', filename],
          inject: true
        }
        if (process.env.NODE_ENV === 'production') {
          conf = merge(conf, {
            minify: {
              removeComments: true,
              collapseWhitespace: true,
              removeAttributeQuotes: true
            },
            chunksSortMode: 'dependency'
          })
        }
        arr.push(new HtmlWebpackPlugin(conf))
      })
      return arr
    }
    /*          ----------------------------    */
    
    
    webpack.base.conf.js 파일
    
    // webpack.base.conf.js   
    
    var path = require('path')
    var utils = require('./utils')
    var config = require('../config')
    var vueLoaderConfig = require('./vue-loader.conf')
    
    function resolve(dir) {
     return path.join(__dirname, '..', dir)
    }
    
    module.exports = {
     /*      ----------------    */
     entry: utils.entries(),
     /*      ----------------    */
     output: {
      path: config.build.assetsRoot,
      filename: '[name].js',
      publicPath: process.env.NODE_ENV === 'production' ?
       config.build.assetsPublicPath :
       config.dev.assetsPublicPath
     },
     resolve: {
      extensions: ['.js', '.vue', '.json'],
      alias: {
       'vue$': 'vue/dist/vue.esm.js',
       '@': resolve('src'),
       'pages': resolve('src/pages'),
       'components': resolve('src/components')
      }
     },
     module: {
      rules: [{
       test: /\.vue$/,
       loader: 'vue-loader',
       options: vueLoaderConfig
      },
      {
       test: /\.js$/,
       loader: 'babel-loader',
       include: [resolve('src'), resolve('test')]
      },
      {
       test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
       loader: 'url-loader',
       options: {
        limit: 10000,
        name: utils.assetsPath('img/[name].[hash:7].[ext]')
       }
      },
      {
       test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
       loader: 'url-loader',
       options: {
        limit: 10000,
        name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
       }
      }
      ]
     }
    }
    
    
    webpack.dev.conf.js 파일
    
    var utils = require('./utils')
    var webpack = require('webpack')
    var config = require('../config')
    var merge = require('webpack-merge')
    var baseWebpackConfig = require('./webpack.base.conf')
    var HtmlWebpackPlugin = require('html-webpack-plugin')
    var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
    
    // add hot-reload related code to entry chunks
    Object.keys(baseWebpackConfig.entry).forEach(function (name) {
     baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
    })
    
    module.exports = merge(baseWebpackConfig, {
     module: {
      rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
     },
     // cheap-module-eval-source-map is faster for development
     devtool: '#cheap-module-eval-source-map',
     plugins: [
      new webpack.DefinePlugin({
       'process.env': config.dev.env
      }),
      // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
      new webpack.HotModuleReplacementPlugin(),
      new webpack.NoEmitOnErrorsPlugin(),
      // https://github.com/ampedandwired/html-webpack-plugin
      /*           -------------    */
      // new HtmlWebpackPlugin({
      //  filename: 'index.html',
      //  template: 'index.html',
      //  inject: true
      // }),
      /*           -------------    */
      new FriendlyErrorsPlugin()
    
      /*    .concat(utils.htmlPlugin()) ------------------ */
     ].concat(utils.htmlPlugin())
    })
    
    
    webpack.prod.conf.js 파일
    
    var path = require('path')
    var utils = require('./utils')
    var webpack = require('webpack')
    var config = require('../config')
    var merge = require('webpack-merge')
    var baseWebpackConfig = require('./webpack.base.conf')
    var CopyWebpackPlugin = require('copy-webpack-plugin')
    var HtmlWebpackPlugin = require('html-webpack-plugin')
    var ExtractTextPlugin = require('extract-text-webpack-plugin')
    var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
    
    var env = config.build.env
    
    var webpackConfig = merge(baseWebpackConfig, {
     module: {
      rules: utils.styleLoaders({
       sourceMap: config.build.productionSourceMap,
       extract: true
      })
     },
     devtool: config.build.productionSourceMap ? '#source-map' : false,
     output: {
      path: config.build.assetsRoot,
      filename: utils.assetsPath('js/[name].[chunkhash].js'),
      chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
     },
     plugins: [
      // http://vuejs.github.io/vue-loader/en/workflow/production.html
      new webpack.DefinePlugin({
       'process.env': env
      }),
      new webpack.optimize.UglifyJsPlugin({
       compress: {
        warnings: false
       },
       sourceMap: true
      }),
      // extract css into its own file
      new ExtractTextPlugin({
       filename: utils.assetsPath('css/[name].[contenthash].css')
      }),
      // Compress extracted CSS. We are using this plugin so that possible
      // duplicated CSS from different components can be deduped.
      new OptimizeCSSPlugin({
       cssProcessorOptions: {
        safe: true
       }
      }),
      // generate dist index.html with correct asset hash for caching.
      // you can customize output by editing /index.html
      // see https://github.com/ampedandwired/html-webpack-plugin
    
      /*           ----------------------    */
      // new HtmlWebpackPlugin({
      //  filename: config.build.index,
      //  template: 'index.html',
      //  inject: true,
      //  minify: {
      //   removeComments: true,
      //   collapseWhitespace: true,
      //   removeAttributeQuotes: true
      //   // more options:
      //   // https://github.com/kangax/html-minifier#options-quick-reference
      //  },
      //  // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      //  chunksSortMode: 'dependency'
      // }),
      /*           ----------------------    */
    
      // split vendor js into its own file
      new webpack.optimize.CommonsChunkPlugin({
       name: 'vendor',
       minChunks: function (module, count) {
        // any required modules inside node_modules are extracted to vendor
        return (
         module.resource &&
         /\.js$/.test(module.resource) &&
         module.resource.indexOf(
          path.join(__dirname, '../node_modules')
         ) === 0
        )
       }
      }),
      // extract webpack runtime and module manifest to its own file in order to
      // prevent vendor hash from being updated whenever app bundle is updated
      new webpack.optimize.CommonsChunkPlugin({
       name: 'manifest',
       chunks: ['vendor']
      }),
      // copy custom static assets
      new CopyWebpackPlugin([{
       from: path.resolve(__dirname, '../static'),
       to: config.build.assetsSubDirectory,
       ignore: ['.*']
      }])
      /*       .concat(utils.htmlPlugin()) ------------------- */
     ].concat(utils.htmlPlugin())
    })
    
    if (config.build.productionGzip) {
     var CompressionWebpackPlugin = require('compression-webpack-plugin')
    
     webpackConfig.plugins.push(
      new CompressionWebpackPlugin({
       asset: '[path].gz[query]',
       algorithm: 'gzip',
       test: new RegExp(
        '\\.(' +
        config.build.productionGzipExtensions.join('|') +
        ')$'
       ),
       threshold: 10240,
       minRatio: 0.8
      })
     )
    }
    
    if (config.build.bundleAnalyzerReport) {
     var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
     webpackConfig.plugins.push(new BundleAnalyzerPlugin())
    }
    
    module.exports = webpackConfig
    
    
    이로써 웹 팩 의 설정 이 끝 났 습 니 다.
    하지만 아직 끝나 지 않 았 습 니 다.다음은 계속 하 겠 습 니 다.
    파일 구조
    
    ├── src
    │  ├── assets
    │  │  └── logo.png
    │  ├── components
    │  │  ├── Hello.vue
    │  │  └── cell.vue
    │  └── pages
    │    ├── cell
    │    │  ├── cell.html
    │    │  ├── cell.js
    │    │  └── cell.vue
    │    └── index
    │      ├── index.html
    │      ├── index.js
    │      ├── index.vue
    │      └── router
    │        └── index.js
    
    src 는 제 가 사용 하 는 프로젝트 파일 입 니 다.assets,components,pages 는 각각 정적 자원 파일,구성 요소 파일,페이지 파일 입 니 다.
    앞의 두 개 는 더 이상 말 하지 않 습 니 다.주로 페이지 파일 에 있 습 니 다.저 는 현재 프로젝트 의 모듈 에 따라 폴 더 를 나 누고 있 습 니 다.당신 도 자신의 수요 에 따라 조정 할 수 있 습 니 다.그리고 각 모듈 에는 vue 파일,js 파일,html 파일 등 세 가지 내용 이 있 습 니 다.이 세 파일 의 역할 은 spa 단일 페이지 응용 시 루트 디 렉 터 리 의 index.html 페이지 템 플 릿,src 파일 의 main.js 와 app.vue 기능 에 해당 합 니 다.
    원래 입구 파일 은 main.js 가 하나 밖 에 없 었 는데 지금 은 여러 페이지 이기 때문에 입구 페이지 가 많아 졌 습 니 다.저 는 현재 두 개 입 니 다.index 와 cell.그 다음 에 포장 하면 dist 파일 에서 두 개의 HTML 파일 을 생 성 합 니 다.index.html 과 cell.html(단일 페이지 응용 을 참고 할 때 포장 은 하나의 index.html 만 생 성 되 고 여기 서 차이 가 있 습 니 다).
    cell 파일 아래 세 개의 파일 은 일반 모드 의 설정 입 니 다.index 를 참고 하면 되 지만 완전히 같 지 않 습 니 다.
    각별히 주의 하 는 곳
    cell.js
    이 파일 에 서 는 쓰기 에 따라 이 렇 겠 지 요.
    
    import Vue from 'Vue'
    import cell from './cell.vue'
    
    new Vue({
      el:'#app',//     cell.html cell.vue    id,      
      teleplate:'<cell/>',
      components:{ cell }
    })
    
    이 설정 이 실 행 될 때(npm run dev)오류 가 발생 합 니 다.
    [Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
    (found in )
    인터넷 의 해석 은 이렇다.
    실행 할 때 템 플 릿 컴 파일 러 를 포함 하지 않 기 때문에 template 옵션 은 지원 되 지 않 습 니 다.render 옵션 만 사용 할 수 있 습 니 다.실행 할 때 구축 하 더 라 도 단일 파일 구성 요소 에 템 플 릿 을 쓸 수 있 습 니 다.단일 파일 구성 요소 의 템 플 릿 은 구축 할 때 render 함수 로 미리 컴 파일 되 기 때 문 입 니 다.실행 시 빌 드 는 독립 빌 드 보다 30%가 볍 고 17.14 Kb min+gzip 크기 입 니 다.
    위의 단락 은 공식 api 의 해석 이다.즉,우리 가 template 를 사용 하고 싶다 면 클 라 이언 트 에서 npm install 후의 vue 를 직접 사용 할 수 없습니다.
    상응하는 수정 방안 도 제시 했다.
    
    resolve: { alias: { 'vue': 'vue/dist/vue.js' } }
    여 기 는 package.json 의 resolve 아래 vue 설정 을 수정 하 는 것 입 니 다.많은 사람들 이 이렇게 수정 하면 좋 겠 다 고 반응 하지만 저 는 이 방법 에 따라 수정 한 후에 도 잘못 보 고 했 습 니 다.그리고 나 서 나 는 위 에서 언급 한 render 함 수 를 생각 했 기 때문에 나의 수정 은 cell.js 파일 을 겨냥 한 것 이다.
    
    import Vue from 'Vue'
    import cell from './cell.vue'
    
    /* eslint-disable no-new */
    new Vue({
     el: '#app',
     render: h => h(cell)
    })
    
    이 안에서 나 는 구성 요소 의 쓰기 대신 render 함수 로 실행 하면 문제 가 없다.
    페이지 이동
    여러 페이지 인 이상 페이지 간 의 상호 점프 와 관련 이 있 을 것 입 니 다.제 프로젝트 의 예 를 들 어 index.html 파일 에서 a 탭 을 클릭 하여 cell.html 로 이동 합 니 다.
    내 가 처음에 쓴 것 은:
    
     <!-- index.html -->
    <a href='../cell/cell.html'></a>
    그러나 이렇게 쓰 면 개발 환경 이 든 최종 테스트 든 404 를 보고 해 이 페이지 를 찾 을 수 없다.
    이렇게 고 쳐 도 된다.
    
     <!-- index.html -->
    <a href='cell.html'></a>
    이렇게 하면 그 는 스스로 cell.html 라 는 파일 을 찾 을 것 이다.
    포 장 된 자원 경로
    npm run build 를 실행 한 후 html 파일 을 열 면 아무것도 볼 수 없습니다.그 이 유 는 js 파일 과 css 파일 을 찾 을 수 없 기 때 문 입 니 다.
    이때 의 파일 구 조 는 다음 과 같다.
    
    ├── dist
    │  ├── js
    │  ├── css
    │  ├── index.html
    │  └── cell.html
    index.html 파일 을 보면 자원 의 참조 경 로 는 다음 과 같 습 니 다.
    /dist/js.........
    이렇게 하면 dist 파일 이 루트 디 렉 터 리 에 있 지 않 으 면 자원 을 찾 을 수 없습니다.
    방법 도 있 지.귀 찮 지 않 으 면 파일 하나,파일 하나,경로 하나,나 처럼 게 으 름 피 우 고 config 아래 index.js 파일 을 수정 해.구체 적 인 방법 은:
    
    build: {
      env: require('./prod.env'),
      index: path.resolve(__dirname, '../dist/index.html'),
      assetsRoot: path.resolve(__dirname, '../dist'),
      assetsSubDirectory: 'static',
      assetsPublicPath: '/',
      productionSourceMap: true,
      // Gzip off by default as many popular static hosts such as
      // Surge or Netlify already gzip all static assets for you.
      // Before setting to `true`, make sure to:
      // npm install --save-dev compression-webpack-plugin
      productionGzip: false,
      productionGzipExtensions: ['js', 'css'],
      // Run the build command with an extra argument to
      // View the bundle analyzer report after build finishes:
      // `npm run build --report`
      // Set to `true` or `false` to always turn it on or off
      bundleAnalyzerReport: process.env.npm_config_report
     },
    
    
    이 안에 있 는
    
    assetsPublicPath: '/',
    ...로 바꾸다
    
    assetsPublicPath: './',
    자줏빛,파일 자원 을 설정 할 때 상대 적 인 경로 에서 자원 을 찾 았 습 니 다.npm run build 를 다시 시도 해 보 세 요.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기