├── renovate.json ├── .gitignore ├── .eslintignore ├── .eslintrc.js ├── lib ├── plugin.js ├── icon-search.svg ├── constants.js ├── module.js └── search.vue ├── babel.config.js ├── .editorconfig ├── jest.config.js ├── .circleci └── config.yml ├── LICENSE ├── CHANGELOG.md ├── package.json ├── example ├── pages │ └── index.vue ├── nuxt.config.js └── docs.json ├── test └── module.test.js └── README.md /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@nuxtjs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.iml 3 | .idea 4 | *.log* 5 | .nuxt 6 | .vscode 7 | .DS_Store 8 | coverage 9 | dist 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Common 2 | node_modules 3 | dist 4 | .nuxt 5 | coverage 6 | 7 | # Plugin 8 | lib/plugin.js 9 | lib/search.vue 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | parser: 'babel-eslint', 5 | sourceType: 'module' 6 | }, 7 | extends: [ 8 | '@nuxtjs' 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /lib/plugin.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Search from './search.vue' 3 | 4 | Vue.component('<%= typeof options.globalComponent === 'string' ? options.globalComponent : 'lunr-search' %>', Search) 5 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', { 5 | targets: { 6 | esmodules: true 7 | } 8 | } 9 | ] 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /lib/icon-search.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /lib/constants.js: -------------------------------------------------------------------------------- 1 | export const placeholderText = 'search' 2 | 3 | export const statusMessages = { 4 | fetching: 'Fetching search index', 5 | loading: 'Loading search index', 6 | searching: 'Searching...', 7 | noresults: 'No results found' 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | collectCoverage: true, 4 | collectCoverageFrom: [ 5 | 'lib/**/*.js', 6 | '!lib/plugin.js' 7 | ], 8 | moduleNameMapper: { 9 | '^~/(.*)$': '/lib/$1', 10 | '^~~$': '', 11 | '^@@$': '', 12 | '^@/(.*)$': '/lib/$1' 13 | }, 14 | transformIgnorePatterns: [ 15 | 'node_modules/(?!(nuxt-i18n))', 16 | ], 17 | transform: { 18 | '^.+\\.js$': 'babel-jest' 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | docker: 5 | - image: circleci/node 6 | steps: 7 | # Checkout repository 8 | - checkout 9 | 10 | # Restore cache 11 | - restore_cache: 12 | key: yarn-cache-{{ checksum "yarn.lock" }} 13 | 14 | # Install dependencies 15 | - run: 16 | name: Install Dependencies 17 | command: NODE_ENV=dev yarn 18 | 19 | # Keep cache 20 | - save_cache: 21 | key: yarn-cache-{{ checksum "yarn.lock" }} 22 | paths: 23 | - "node_modules" 24 | 25 | # Lint 26 | - run: 27 | name: Lint 28 | command: yarn lint 29 | 30 | # Tests 31 | - run: 32 | name: Tests 33 | command: yarn jest 34 | 35 | # Coverage 36 | - run: 37 | name: Coverage 38 | command: yarn codecov 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) pimlie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### [0.3.2](https://github.com/nuxt-community/lunr-module/compare/v0.3.1...v0.3.2) (2020-11-28) 6 | 7 | ### [0.3.1](https://github.com/nuxt-community/lunr-module/compare/v0.3.0...v0.3.1) (2019-09-15) 8 | 9 | 10 | ### Bug Fixes 11 | 12 | * only call concat when array ([6054e08](https://github.com/nuxt-community/lunr-module/commit/6054e08)) 13 | 14 | ## [0.3.0](https://github.com/nuxt-community/lunr-module/compare/v0.2.0...v0.3.0) (2019-09-15) 15 | 16 | 17 | ### Features 18 | 19 | * add language stemming map ([f885a72](https://github.com/nuxt-community/lunr-module/commit/f885a72)) 20 | 21 | ## [0.2.0](https://github.com/nuxt-community/lunr-module/compare/v0.1.1...v0.2.0) (2019-08-15) 22 | 23 | 24 | ### Features 25 | 26 | * make placeholder text and status messages configurable ([552fea5](https://github.com/nuxt-community/lunr-module/commit/552fea5)) 27 | 28 | ### [0.1.1](https://github.com/nuxt-community/lunr-module/compare/v0.1.0...v0.1.1) (2019-08-11) 29 | 30 | 31 | ### Bug Fixes 32 | 33 | * improve lang/locale usage ([f8f7835](https://github.com/nuxt-community/lunr-module/commit/f8f7835)) 34 | * use tapPromise in webpack hook ([50f11a7](https://github.com/nuxt-community/lunr-module/commit/50f11a7)) 35 | 36 | ## 0.1.0 (2019-08-10) 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nuxtjs/lunr-module", 3 | "version": "0.3.2", 4 | "description": "Full-text search with pre-build indexes for Nuxt.js using lunr.js", 5 | "license": "MIT", 6 | "contributors": [ 7 | { 8 | "name": "pimlie " 9 | } 10 | ], 11 | "main": "lib/module.js", 12 | "repository": "https://github.com/nuxt-community/lunr-module", 13 | "publishConfig": { 14 | "access": "public" 15 | }, 16 | "scripts": { 17 | "dev": "nuxt example", 18 | "build": "nuxt build example", 19 | "start": "nuxt start example", 20 | "lint": "eslint --ext .js,.vue example lib test", 21 | "lint:template": "eslint --no-ignore --ext .js,.vue example/.nuxt/lunr/", 22 | "test": "jest", 23 | "release": "yarn lint && yarn test && yarn lint:template && standard-version" 24 | }, 25 | "files": [ 26 | "lib" 27 | ], 28 | "dependencies": { 29 | "consola": "^2.15.0", 30 | "lunr": "^2.3.9", 31 | "lunr-languages": "^1.4.0" 32 | }, 33 | "devDependencies": { 34 | "@babel/core": "latest", 35 | "@babel/preset-env": "latest", 36 | "@commitlint/cli": "latest", 37 | "@commitlint/config-conventional": "latest", 38 | "@nuxtjs/eslint-config": "latest", 39 | "babel-eslint": "latest", 40 | "babel-jest": "latest", 41 | "codecov": "latest", 42 | "eslint": "latest", 43 | "get-port": "latest", 44 | "jest": "latest", 45 | "jsdom": "^16.4.0", 46 | "nuxt-edge": "latest", 47 | "nuxt-i18n": "6.15.4", 48 | "standard-version": "latest", 49 | "tib": "^0.7.4" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /example/pages/index.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 60 | 61 | 105 | -------------------------------------------------------------------------------- /test/module.test.js: -------------------------------------------------------------------------------- 1 | import { Nuxt, Builder, Generator } from 'nuxt-edge' 2 | import { waitFor } from '@nuxt/utils-edge' 3 | import consola from 'consola' 4 | import getPort from 'get-port' 5 | import { createBrowser } from 'tib' 6 | 7 | jest.setTimeout(30000) 8 | consola.mockTypes(() => jest.fn()) 9 | 10 | describe('basic', () => { 11 | let browser 12 | 13 | afterAll(async () => { 14 | await browser.close() 15 | }) 16 | 17 | test('build fixture', async () => { 18 | const config = await import('../example/nuxt.config').then(m => m.default || m) 19 | config.dev = false 20 | 21 | const nuxt = new Nuxt(config) 22 | await nuxt.ready() 23 | 24 | const builder = await new Builder(nuxt) 25 | const generator = await new Generator(nuxt, builder) 26 | await generator.generate({ init: true, build: true }) 27 | 28 | browser = await createBrowser('jsdom', { 29 | staticServer: { 30 | port: await getPort(), 31 | folder: nuxt.options.generate.dir 32 | } 33 | }) 34 | browser.setLogLevel(['warn', 'error', 'log', 'info']) 35 | 36 | expect(consola.warn).toHaveBeenCalledTimes(2) 37 | expect(consola.warn).toHaveBeenCalledWith(expect.stringContaining('Unable to index document'), expect.anything()) 38 | expect(consola.warn).toHaveBeenCalledWith(expect.stringContaining('locale \'fr\' not supported')) 39 | }) 40 | 41 | test('search /en/', async () => { 42 | const url = browser.getUrl('/en/') 43 | const page = await browser.page(url) 44 | 45 | await waitFor(500) 46 | 47 | expect(await page.getText('h1')).toBe('Moonwalkers (en)') 48 | expect(await page.getAttribute('.lunr-input', 'placeholder')).toBe('search') 49 | expect(await page.getElementCount('.lunr-results li')).toBe(0) 50 | 51 | const input = page.document.querySelector('input') 52 | input.value = 'test' 53 | const event = new page.window.Event('input') 54 | input.dispatchEvent(event) 55 | 56 | await waitFor(500) 57 | 58 | expect(await page.getElementCount('.lunr-results li')).toBe(3) 59 | }) 60 | 61 | test('search /af/', async () => { 62 | const url = browser.getUrl('/af/') 63 | const page = await browser.page(url) 64 | 65 | await waitFor(500) 66 | 67 | expect(await page.getText('h1')).toBe('Moonwalkers (af)') 68 | expect(await page.getAttribute('.lunr-input', 'placeholder')).toBe('zoek') 69 | expect(await page.getElementCount('.lunr-results li')).toBe(0) 70 | 71 | const input = page.document.querySelector('input') 72 | input.value = 'test' 73 | const event = new page.window.Event('input') 74 | input.dispatchEvent(event) 75 | 76 | await waitFor(500) 77 | 78 | expect(await page.getElementCount('.lunr-results li')).toBe(1) 79 | }) 80 | }) 81 | -------------------------------------------------------------------------------- /example/nuxt.config.js: -------------------------------------------------------------------------------- 1 | import { resolve } from 'path' 2 | import docs from './docs' 3 | 4 | export default { 5 | rootDir: resolve(__dirname, '..'), 6 | buildDir: resolve(__dirname, '.nuxt'), 7 | srcDir: __dirname, 8 | render: { 9 | resourceHints: false 10 | }, 11 | modules: [ 12 | 'nuxt-i18n', 13 | { 14 | handler: require('../'), 15 | options: { 16 | globalComponent: 'GlobalLunr', 17 | css: false, 18 | path: 'my-crazy-search-index-path', 19 | defaultLanguage: 'french', 20 | languages: ['en'], 21 | languageStemmerMap: { 22 | af: 'nl' 23 | }, 24 | fields: ['name', 'body'] 25 | } 26 | } 27 | ], 28 | i18n: { 29 | detectBrowserLanguage: false, 30 | locales: ['en', 'fr', 'af'], 31 | defaultLocale: 'en', 32 | strategy: 'prefix_and_default', 33 | vueI18n: { 34 | messages: { 35 | en: { 36 | 'lunr-module': { 37 | placeholderText: 'search' 38 | } 39 | }, 40 | fr: { 41 | 'lunr-module': { 42 | placeholderText: 'chercher' 43 | } 44 | }, 45 | af: { 46 | 'lunr-module': { 47 | placeholderText: 'zoek' 48 | } 49 | } 50 | } 51 | } 52 | }, 53 | hooks: { 54 | ready (nuxt) { 55 | let documentIndex = 1 56 | 57 | // this call is just for increasing coverage 58 | // (the example is also just as test fixture) 59 | nuxt.callHook('lunr:document') 60 | 61 | // trigger 'not adding doc' warning to increase coverage 62 | nuxt.callHook('lunr:document', { 63 | document: true 64 | }) 65 | 66 | for (const doc of docs) { 67 | nuxt.callHook('lunr:document', { 68 | locale: documentIndex === 1 ? 'fr' : (documentIndex % 2 ? 'en' : 'af'), 69 | document: { 70 | id: documentIndex, 71 | ...doc 72 | }, 73 | /* !! WARNING: Do NOT copy this blindly !! 74 | * 75 | * When adding the full document as meta the json of your 76 | * search index will become very large very quickly. Parsing that 77 | * json on the client (especially mobile clients) could become a 78 | * performance issue 79 | * 80 | * Normally you'd only need to include 'enough' meta info to properly 81 | * recognise the document and to display your search results. 82 | * E.g. The path and title of the page the document refers to, but 83 | * _not_ the full text that was used for indexing 84 | */ 85 | meta: doc 86 | }) 87 | documentIndex++ 88 | } 89 | } 90 | }, 91 | build: { 92 | terser: false 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/module.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import fs from 'fs' 3 | import util from 'util' 4 | import consola from 'consola' 5 | import lunr from 'lunr' 6 | import lunrStemmer from 'lunr-languages/lunr.stemmer.support' 7 | import { placeholderText, statusMessages } from './constants' 8 | 9 | const readDir = util.promisify(fs.readdir) 10 | const logger = process.env.NODE_ENV === 'test' ? consola : consola.withScope('lunr-module') 11 | const normalizeLanguage = locale => (locale || '').substr(0, 2).toLowerCase() 12 | 13 | const defaultOptions = { 14 | includeComponent: true, 15 | globalComponent: false, 16 | css: true, 17 | defaultLanguage: 'en', 18 | languages: undefined, 19 | languageStemmerMap: {}, 20 | path: 'search-index', 21 | placeholderText, 22 | statusMessages, 23 | ref: 'id', 24 | fields: [ 25 | 'title', 26 | 'body' 27 | ] 28 | } 29 | 30 | module.exports = async function LunrModule (options = {}) { 31 | const nuxt = this.nuxt 32 | 33 | options = { 34 | ...defaultOptions, 35 | ...nuxt.options.lunr, 36 | ...options, 37 | supportedLanguages: [] 38 | } 39 | 40 | if (options.path !== defaultOptions.path) { 41 | options.path = options.path.replace(/^\/+|\/+$/g, '') 42 | } 43 | 44 | const useI18N = nuxt.options.i18n && nuxt.options.i18n.locales.length 45 | let usedLocales = [] 46 | /* istanbul ignore next */ 47 | if (typeof options.languages === 'string') { 48 | usedLocales = [options.languages] 49 | } else if (Array.isArray(options.languages)) { 50 | usedLocales = options.languages 51 | /* istanbul ignore next */ 52 | } else if (useI18N) { 53 | usedLocales = nuxt.options.i18n.locales 54 | } 55 | 56 | if (Array.isArray(usedLocales)) { 57 | usedLocales = usedLocales.concat(Object.values(options.languageStemmerMap)) 58 | 59 | const allSupportedLanguages = [] 60 | 61 | const languagesPath = path.dirname(require.resolve('lunr-languages/package.json')) 62 | if (languagesPath) { 63 | const files = await readDir(languagesPath) 64 | for (const file of files) { 65 | if (!file.startsWith('lunr.') || !file.endsWith('.js')) { 66 | continue 67 | } 68 | 69 | const [, language] = file.toLowerCase().split('.') 70 | 71 | if (language && language.length === 2) { 72 | allSupportedLanguages.push(language) 73 | } 74 | } 75 | } 76 | 77 | options.supportedLanguages = usedLocales 78 | .map((locale) => { 79 | locale = typeof locale === 'string' ? locale : locale.code 80 | 81 | const language = normalizeLanguage(locale) 82 | 83 | if (allSupportedLanguages.includes(language)) { 84 | return language 85 | } 86 | 87 | return false 88 | }) 89 | .filter(Boolean) 90 | } 91 | 92 | if (options.defaultLanguage !== 'en' && !options.supportedLanguages.includes(options.defaultLanguage)) { 93 | options.defaultLanguage = defaultOptions.defaultLanguage 94 | } 95 | 96 | if (options.supportedLanguages.length) { 97 | lunrStemmer(lunr) 98 | } 99 | 100 | let metas 101 | const documents = {} 102 | nuxt.hook('lunr:document', ({ locale = 'en', document, meta } = {}) => { 103 | if (!document) { 104 | return 105 | } 106 | 107 | const language = normalizeLanguage(locale) 108 | let stemmerLanguage = options.languageStemmerMap[language] || language 109 | 110 | if (stemmerLanguage !== 'en' && !options.supportedLanguages.includes(stemmerLanguage)) { 111 | logger.warn(`locale '${locale}' not supported, falling back to ${options.defaultLanguage} for stemming`) 112 | stemmerLanguage = options.defaultLanguage 113 | 114 | options.languageStemmerMap[language] = stemmerLanguage 115 | } 116 | 117 | if (!documents[language]) { 118 | documents[language] = [] 119 | } 120 | 121 | if (meta && (!metas || !metas[language])) { 122 | metas = metas || {} 123 | metas[language] = {} 124 | } 125 | 126 | const documentRef = document[options.ref] 127 | if (!documentRef) { 128 | logger.warn(`Unable to index document, does not contain a ref '${options.ref}'. Document:`, document) 129 | return 130 | } 131 | 132 | documents[language].push(document) 133 | 134 | if (meta) { 135 | metas[language][documentRef] = meta 136 | } 137 | }) 138 | 139 | const webpackPlugin = compilation => createSearchIndexAssets(compilation, documents) 140 | this.options.build.plugins.push({ 141 | apply (compiler) { 142 | compiler.hooks.emit.tapPromise('LunrModulePlugin', webpackPlugin) 143 | } 144 | }) 145 | 146 | this.extendBuild((config) => { 147 | config.resolve.alias['lunr-module'] = path.join(this.options.buildDir, 'lunr') 148 | }) 149 | 150 | if (options.includeComponent || options.globalComponent) { 151 | this.addTemplate({ 152 | src: path.resolve(__dirname, 'icon-search.svg'), 153 | fileName: 'lunr/icon-search.svg' 154 | }) 155 | 156 | this.addTemplate({ 157 | src: path.resolve(__dirname, 'search.vue'), 158 | fileName: 'lunr/search.vue', 159 | options: { 160 | ...options, 161 | useI18N, 162 | publicPath: nuxt.options.build.publicPath 163 | } 164 | }) 165 | } 166 | 167 | if (options.globalComponent) { 168 | this.addPlugin({ 169 | src: path.resolve(__dirname, 'plugin.js'), 170 | fileName: 'lunr/plugin.js', 171 | options 172 | }) 173 | } 174 | 175 | async function createSearchIndex (language, documents) { 176 | // retrieve the mapped language we should use for stemming 177 | const stemmerLanguage = options.languageStemmerMap[language] 178 | 179 | // this will be set to false for en, but en is supported by default 180 | // and doesnt require any extra lunr modules 181 | const isSupportedLanguage = options.supportedLanguages.includes(stemmerLanguage) 182 | 183 | if (isSupportedLanguage && !lunr[stemmerLanguage]) { 184 | const lunrLanguage = await import('lunr-languages/lunr.' + stemmerLanguage).then(m => m.default || m) 185 | lunrLanguage(lunr) 186 | } 187 | 188 | let lunrBuilder 189 | lunr(builder => (lunrBuilder = builder)) 190 | await nuxt.callHook('lunr:index:beforeCreate', { 191 | locale: language, 192 | stemmerLanguage, 193 | builder: lunrBuilder 194 | }) 195 | 196 | if (isSupportedLanguage) { 197 | lunrBuilder.use(lunr[stemmerLanguage]) 198 | } 199 | 200 | lunrBuilder.ref(options.ref) 201 | for (const field of options.fields) { 202 | lunrBuilder.field(field) 203 | } 204 | 205 | await nuxt.callHook('lunr:index:created', { 206 | locale: language, 207 | stemmerLanguage, 208 | builder: lunrBuilder 209 | }) 210 | 211 | for (const document of documents) { 212 | lunrBuilder.add(document) 213 | } 214 | 215 | const searchIndex = lunrBuilder.build() 216 | 217 | await nuxt.callHook('lunr:index:done', { 218 | locale: language, 219 | stemmerLanguage, 220 | builder: lunrBuilder, 221 | index: searchIndex 222 | }) 223 | 224 | return searchIndex.toJSON() 225 | } 226 | 227 | async function createSearchIndexAssets (compilation, documents) { 228 | for (const language in documents) { 229 | const searchJson = await createSearchIndex(language, documents[language]) 230 | 231 | if (metas && metas[language]) { 232 | searchJson.metas = metas[language] 233 | } 234 | 235 | await nuxt.callHook('lunr:asset', { 236 | locale: language, 237 | json: searchJson 238 | }) 239 | 240 | const jsonString = JSON.stringify(searchJson) 241 | 242 | compilation.assets[`${options.path}/${language}.json`] = { 243 | source: () => jsonString, 244 | size: () => jsonString.length 245 | } 246 | } 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lunr.js module 2 | 3 | [![npm version][npm-version-src]][npm-version-href] 4 | [![npm downloads][npm-downloads-src]][npm-downloads-href] 5 | [![Circle CI][circle-ci-src]][circle-ci-href] 6 | [![Codecov][codecov-src]][codecov-href] 7 | [![License][license-src]][license-href] 8 | 9 | > Full-text search with pre-build indexes for Nuxt.js using [lunr.js](https://lunrjs.com/) 10 | 11 | During the build phase of Nuxt.js you can add documents to the search index builder by calling the nuxt hook `lunr:document`. If you have configured and pass a [supported][lunr-supported-lang] locale along the document, the index will be build using the lunr stemmer for the specified language. As the lunr search index only holds references to your documents, you can optionally pass a meta prop along with the document which will be added to the search index as well. 12 | 13 | [📖 **Release Notes**](./CHANGELOG.md) 14 | 15 | ## Setup 16 | 17 | 1. Add `@nuxtjs/lunr-module` dependency to your project 18 | 19 | ```bash 20 | $ yarn add @nuxtjs/lunr-module # or npm install @nuxtjs/lunr-module 21 | ``` 22 | 23 | 2. Add `@nuxtjs/lunr-module` to the `modules` section of `nuxt.config.js` 24 | 25 | ```js 26 | { 27 | modules: [ 28 | // Simple usage 29 | '@nuxtjs/lunr-module', 30 | 31 | // With options 32 | { 33 | src: '@nuxtjs/lunr-module', 34 | // These are the default options: 35 | /* 36 | options: { 37 | includeComponent: true, 38 | globalComponent: false, 39 | css: true, 40 | defaultLanguage: 'en', 41 | languages: false, 42 | path: 'search-index', 43 | ref: 'id', 44 | fields: [ 45 | 'title', 46 | 'body' 47 | ] 48 | } */ 49 | } 50 | ] 51 | } 52 | ``` 53 | 54 | ## Documentation 55 | 56 | ### Adding documents to search index 57 | 58 | Add documents by calling the nuxt hook `lunr:documents` as follows: 59 | 60 | ```js 61 | const document = { 62 | id: 1, 63 | title: 'My Title', 64 | body: 'The body' 65 | } 66 | 67 | const meta = { 68 | href: '/link/to/page', 69 | title: document.title 70 | } 71 | 72 | nuxt.callHook('lunr:document', ({ 73 | locale: 'af', // optional, default en 74 | document, 75 | meta // optional 76 | }) 77 | ``` 78 | 79 | #### Locale support 80 | 81 | By configuring the locales options you can indicate for which [supported][lunr-supported-lang] languages a search index should be created. If you pass any other locale with a document it will be added to the [`defaultLanguage`](#defaultlanguage) search index (and a warning will be printed). 82 | 83 | > Multiple languages equals multiple search indexes 84 | 85 | English is supported by default in Lunr, when you only have English documents you dont have to configure or pass any locale. 86 | 87 | ##### Language vs Locale 88 | 89 | A locale can consist of just a language or include a territory, you can use either of them. So both just the language (e.g. _nl_) as including the territory (e.g. _nl_NL_) will work 90 | 91 | ##### nuxt-i18n integration 92 | 93 | If this module detects your project uses [nuxt-i18n](https://github.com/nuxt-community/nuxt-i18n) then the configured locales for nuxt-i18n will be automatically added. You dont have to configure the locales you use twice unless you want to use different locales (e.g. only one) for the search index. 94 | 95 | ### Add a search component to your website 96 | 97 | This module includes a search component which you can use on your website. Use it's default slot to display your search results using the properties passed in the meta prop 98 | 99 | ```vue 100 | 110 | 111 | 120 | ``` 121 | 122 | ## Performance considerations 123 | 124 | ### Use an integer as document reference 125 | 126 | The document reference (defined by [option.ref](#ref)) is used in the search index to link all stemmed word segments. If you would use e.g. the page path as the document reference, then for a page with path `/en/offices/emea/nl/contact` that string value will be used to link all the stemmed word segments. This could increases the size of the search index massively, therefor its recommended to create a numeric document reference and use the `meta` property to add the page path for that document reference only once to the search index. 127 | 128 | ### Load search component dynamically 129 | Lunr doesnt export ES6 modules and can't be tree-shaked. Using this module adds `~8.5KB` + `~2KB` for every other language then English to your bundle (gzipped). See example above for a dynamic import which makes sure the lunr imports are not included in your vendors bundle 130 | 131 | ### Keep an eye on the search index size in general 132 | The search index is saved as a json file and thus needs to be parsed on the client. If the json of your search index becomes very large it could be an issue on (mobile) clients. E.g. Safari on iOS limits each top-level entry-point to run for max 10 seconds. See [this](https://github.com/olivernn/lunr.js/issues/330) Lunr.js issue for a possible workaround. 133 | 134 | ## Reference 135 | 136 | ### Options 137 | 138 | #### includeComponent 139 | - type `Boolean` 140 | - default `true` 141 | 142 | If true then the default search component will be added to your Nuxt project 143 | 144 | > You can import the component using the webpack alias `lunr-module/search` 145 | 146 | #### globalComponent 147 | - type `Boolean`, `String` 148 | - default `false` 149 | 150 | If truthy then a plugin will be added to your project which installs the search component globally 151 | 152 | > Setting this option implies `includeComponent: true` 153 | 154 | By default the search component will be registered as `lunr-search`, if you wish this name you can set this option to a string with the name you wish to use 155 | 156 | ```js 157 | globalComponent: 'my-global-lunr-search' 158 | ... 159 | 162 | ``` 163 | 164 | #### css 165 | - type `Boolean` 166 | - default `true` 167 | 168 | If the search component is included, this option determines if the default css styles should be included or not 169 | 170 | #### defaultLanguage 171 | - type `String` 172 | - default `'en'` 173 | 174 | The default language to use. This is also the fall-back language if you pass a document with a non-supported locale 175 | 176 | #### languages 177 | - type `String`, `Array` 178 | - default `undefined` 179 | 180 | A string or array of the languages for which a search index needs to be created. 181 | 182 | Although this option might look redundant (i.e. why not just create a search index for every language which is passed), it provides a check to prevent 'rogue' documents from being indexed into a separate index. 183 | 184 | #### languageStemmerMap 185 | - type `Object` 186 | - default `{}` 187 | 188 | An object which contains a map of unsupported languages to supported stemming languages (by lunr). Use this to specify which stemming language should be used if you want to build a search index for a language which is not supported by lunr (yet). 189 | 190 | #### path 191 | - type `String` 192 | - default `search-index` 193 | 194 | On build of your project the created search indexes will be emitted as webpack assets. This option determines the path under `nuxt.publicPath` should be used. 195 | 196 | > With default configurations for Nuxt.js and this module the English search index is available under `/_nuxt/search-index/en.json` 197 | 198 | #### ref 199 | - type `String` 200 | - default `id` 201 | 202 | The name of the property in your document which specifies what as reference should be used for this document in the search index 203 | 204 | #### fields 205 | - type `Array` 206 | - default `['title', 'body']` 207 | 208 | The property names in your document which will be indexed 209 | 210 | #### placeholderText 211 | - type `String` 212 | - default `Search` 213 | 214 | The text that is put in the placeholder of the search input field. If you are using nuxt-i18n, you can also provide a translation with key `lunr-module.placeholderText` 215 | 216 | #### statusMessages 217 | - type `Array` 218 | - default `{ 219 | fetching: 'Fetching search index', 220 | loading: 'Loading search index', 221 | searching: 'Searching...', 222 | noresults: 'No results found' 223 | }` 224 | 225 | The status messages which are displayed during the search life cycle. If you are using nuxt-i18n, you can also provide a translation with key `lunr-module.${key}`. Eg use `lunr-module.noresults` to provide a translation for the no results found status. 226 | 227 | ### Hooks (Listening) 228 | 229 | > use `nuxt.callHook(, )` if you wish to use these hooks 230 | 231 | #### lunr:document 232 | - arg: `({ locale?, document, meta? })` 233 | 234 | The main hook which is used to add documents to the search index. You need to pass an object as described. Both locale as meta are optional. If no locale is passed the `defaultLanguage` will be used 235 | 236 | ### Hooks (Emitting) 237 | 238 | > use `nuxt.hook(, )` if you wish to use these hooks. The callback function receives the listed arguments 239 | 240 | #### lunr:index:beforeCreate 241 | - arg: `({ locale, builder })` 242 | 243 | > Use this hook if you e.g. want to register custom lunr plugins 244 | 245 | This hook is called after the lunr builder is instantiated but before language plugins have been added or any refs and fields are set 246 | 247 | #### lunr:index:created 248 | - arg: `({ locale, builder })` 249 | 250 | > Use this hook if you e.g. want to add extra documents to an index 251 | 252 | This hook is called when the lunr builder has been setup, just before the documents are added to the index. 253 | 254 | #### lunr:index:done 255 | - arg: `({ locale, builder, index })` 256 | 257 | > Use this hook if you wish to interact with the index before exporting it 258 | 259 | This hook is called just before the index is exported as an json object 260 | 261 | #### lunr:asset 262 | - arg: `({ locale, json })` 263 | 264 | > Use this hook if you wish to manipulate the json which is emitted as search index for the locale 265 | 266 | This hook is called during webpack compilation just before the search index is prepared to be emitted as asset 267 | 268 | ## Development 269 | 270 | 1. Clone this repository 271 | 2. Install dependencies using `yarn install` or `npm install` 272 | 3. Start development server using `npm run dev` 273 | 274 | ## License 275 | 276 | [MIT License](./LICENSE) 277 | 278 | Copyright (c) pimlie 279 | 280 | 281 | [npm-version-src]: https://img.shields.io/npm/v/@nuxtjs/lunr-module/latest.svg?style=flat-square 282 | [npm-version-href]: https://npmjs.com/package/@nuxtjs/lunr-module 283 | 284 | [npm-downloads-src]: https://img.shields.io/npm/dt/@nuxtjs/lunr-module.svg?style=flat-square 285 | [npm-downloads-href]: https://npmjs.com/package/@nuxtjs/lunr-module 286 | 287 | [circle-ci-src]: https://img.shields.io/circleci/project/github/nuxt-community/lunr-module.svg?style=flat-square 288 | [circle-ci-href]: https://circleci.com/gh/nuxt-community/lunr-module 289 | 290 | [codecov-src]: https://img.shields.io/codecov/c/github/nuxt-community/lunr-module.svg?style=flat-square 291 | [codecov-href]: https://codecov.io/gh/nuxt-community/lunr-module 292 | 293 | [license-src]: https://img.shields.io/npm/l/@nuxtjs/lunr-module.svg?style=flat-square 294 | [license-href]: https://npmjs.com/package/@nuxtjs/lunr-module 295 | 296 | [lunr-supported-lang]: https://lunrjs.com/guides/language_support.html 297 | -------------------------------------------------------------------------------- /lib/search.vue: -------------------------------------------------------------------------------- 1 | 59 | 60 | 373 | <% if (options.css) { %> 374 | 435 | <% } %> 436 | -------------------------------------------------------------------------------- /example/docs.json: -------------------------------------------------------------------------------- 1 | [{"name":"alan bean","body":"Alan Bean was one of the third group of astronauts named by NASA in October 1963. He served as backup astronaut for the Gemini 10 and Apollo 9 missions. Captain Bean was lunar module pilot on Apollo 12, mans second lunar landing. In November 1969, Captain Bean and Captain Pete Conrad landed in the moons Ocean of Stormsafter a flight of some 250,000 miles. They explored the lunar surface, deployed several lunar surface experiments, and installed the first nuclear power generator station on the moon to provide the power source. Captain Richard Gordon remained in lunar orbit photographing landing sites for future missions. Captain Bean was spacecraft commander of Skylab Mission II (SL-3), July 29 to September 25, 1973. With him on the 59-day, 24,400,000 mile world record setting flight were scientist-astronaut Dr. Owen K. Garriott and Marine Corps Lieutenant Colonel Jack R. Lousma. Mission II accomplished 150% of its pre-mission forecast goals. On his next assignment, Captain Bean was backup spacecraft commander of the United States flight crew for the joint American-Russian Apollo-Soyuz Test Project. Captain Bean has logged 1,671 hours and 45 minutes in spaceof which 10 hours and 26 minutes were spent in EVAs on the moon and in earth orbit."},{"name":"alan shepard","body":"Rear Admiral Shepard was one of the Mercury astronauts named by NASA in April 1959, and he holds the distinction of being the first American to journey into space. On May 5, 1961, in the Freedom 7 spacecraft, he was launched by a Redstone vehicle on a ballistic trajectory suborbital flight--a flight which carried him to an altitude of 116 statute miles and to a landing point 302 statute miles down the Atlantic Missile Range. In 1963, he was designated Chief of the Astronaut Office with responsibility for monitoring the coordination, scheduling, and control of all activities involving NASA astronauts. This included monitoring the development and implementation of effective training programs to assure the flight readiness of available pilot/non-pilot personnel for assignment to crew positions on manned space flights; furnishing pilot evaluations applicable to the design, construction, and operations of spacecraft systems and related equipment; and providing qualitative scientific and engineering observations to facilitate overall mission planning, formulation of feasible operational procedures, and selection and conduct of specific experiments for each flight. He was restored to full flight status in May 1969, following corrective surgery for an inner ear disorder. Shepard made his second space flight as spacecraft commander on Apollo 14, January 31 - February 9, 1971. He was accompanied on man's third lunar landing mission by Stuart A. Roosa, command module pilot, and Edgar D. Mitchell, lunar module pilot. Maneuvering their lunar module, \"Antares,\" to a landing in the hilly upland Fra Mauro region of the moon, Shepard and Mitchell subsequently deployed and activated various scientific equipment and experiments and collected almost 100 pounds of lunar samples for return to earth. Other Apollo 14 achievements included: first use of Mobile Equipment Transporter (MET); largest payload placed in lunar orbit; longest distance traversed on the lunar surface; largest payload returned from the lunar surface; longest lunar surface stay time (33 hours); longest lunar surface EVA (9 hours and 17 minutes); first use of shortened lunar orbit rendezvous techniques; first use of colored TV with new vidicon tube on lunar surface; and first extensive orbital science period conducted during CSM solo operations."},{"name":"buzz aldrin","body":"Aldrin was one of the third group of astronauts named by NASA in October 1963. On November 11, 1966, he and command pilot James Lovell were launched into space in the Gemini 12 spacecraft on a 4-day flight, which brought the Gemini program to a successful close. Aldrin established a new record for extravehicular activity (EVA), spending 5-1/2 hours outside the spacecraft. He served as lunar module pilot for Apollo 11, July 16-24, 1969, the first manned lunar landing mission. Aldrin followed Neil Armstrong onto the lunar surface on July 20, 1969, completing a 2-hour and 15 minute lunar EVA. In July 1971, Aldrin resigned from NASA. Aldrin has logged 289 hours and 53 minutes in space, of which, 7 hours and 52 minutes were spent in EVA."},{"name":"charles duke","body":"Duke was one of the 19 astronauts selected by NASA in April 1966. He served as member of the astronaut support crew for the Apollo 10 flight. He was CAPCOM for Apollo 11, the first landing on the Moon and he served as backup lunar module pilot on Apollo 13. Duke served as lunar module pilot of Apollo 16, April 16-27, 1972. He was accompanied on the fifth manned lunar landing mission by John W. Young (spacecraft commander) and Thomas K. Mattingly II (command module pilot). Apollo 16 was the first scientific expedition to inspect, survey, and sample materials and surface features in the Descartes region of the rugged lunar highlands. Duke and Young commenced their record setting lunar surface stay of 71 hours and 14 minutes by maneuvering the lunar module \"Orion\" to a landing on the rough Cayley Plains. In three subsequent excursions onto the lunar surface, they each logged 20 hours and 15 minutes in extravehicular activities involving the emplacement and activation of scientific equipment and experiments, the collection of nearly 213 pounds of rock and soil samples, and the evaluation and use of Rover-2 over the roughest and blockiest surface yet encountered on the moon. Other Apollo 16 achievements included the largest payload placed in lunar orbit (76, 109 pounds); first cosmic ray detector deployed on lunar surface; first lunar observatory with the far UV camera; and longest in-flight EVA from a command module during transearth coast (1 hour and 13 minutes). The latter feat was accomplished by Mattingly when he ventured out to \"Casper's\" SIM-bay for the retrieval of vital film cassettes from the panoramic and mapping cameras. Apollo 16 concluded with a Pacific Ocean splashdown and subsequent recovery by the USS TICONDEROGA. With the completion of his first space flight, Duke has logged 265 hours in space and over 21 hours of extra vehicular activity. Duke also served as backup lunar module pilot for Apollo 17."},{"name":"david scott","body":"Scott was one of the third group of astronauts named by NASA in October 1963. On March 16, 1966, he and command pilot Neil Armstrong were launched into space on the Gemini 8 mission--a flight originally scheduled to last three days but terminated early due to a malfunctioning thruster. The crew performed the first successful docking of two vehicles in space and demonstrated great piloting skill in overcoming the thruster problem and bringing the spacecraft to a safe landing. Scott served as command module pilot for Apollo 9, March 3-13, 1969. This was the third manned flight in the Apollo series, the second to be launched by a Saturn V, and the first to complete a comprehensive earth-orbital qualification and verification test of a \"fully configured Apollo spacecraft.\" The ten-day flight provided vital information previously not available on the operational performance, stability, and reliability of lunar module propulsion and life support systems. Highlight of this evaluation was completion of a critical lunar-orbit rendezvous simulation and subsequent docking, initiated by James McDivitt and Russell Schweickart from within the lunar module at a separation distance which exceeded 100 miles from the command/service module piloted by Scott. The crew also demonstrated and confirmed the operational feasibility of crew transfer and extravehicular activity techniques and equipment, with Schweickart completing a 46-minute EVA outside the lunar module. During this period, Dave Scott completed a 1-hour stand-up EVA in the open command module hatch photographing Schweickart's activities and also retrieving thermal samples from the command module exterior. Apollo 9 splashed down less than four miles from the helicopter carrier USS GUADALCANAL. In his next assignment, Scott was designated backup spacecraft commander for Apollo 12. He made his third space flight as spacecraft commander of Apollo 15, July 26 - August 7, 1971. His companions on the flight were Alfred M. Worden (command module pilot) and James B. Irwin (lunar module pilot). Apollo 15 was the fourth manned lunar landing mission and the first to visit and explore the moon's Hadley Rille and Apennine Mountains which are located on the southeast edge of the Mare Imbrium (Sea of Rains). The lunar module, \"Falcon,\" remained on the lunar surface for 66 hours and 54 minutes (setting a new record for lunar surface stay time) and Scott and Irwin logged 18 hours and 35 minutes each in extravehicular activities conducted during three separate excursions onto the lunar surface. Using \"Rover-1\" to transport themselves and their equipment along portions of Hadley Rille and the Apennine Mountains, Scott and Irwin performed a selenological inspection and survey of the area and collected 180 pounds of lunar surface materials. They deployed an ALSEP package which involved the emplacement and activation of surface experiments, and their lunar surface activities were televised using a TV camera which was operated remotely by ground controllers stationed in the mission control center located at Houston, Texas. Other Apollo 15 achievements include: largest payloads ever placed into earth and lunar orbits; first scientific instrument module bay flown and operated on an Apollo spacecraft; longest distance traversed on lunar surface; first use of a lunar surface navigation device (mounted on Rover-1); first subsatellite launched in lunar orbit; and first extravehicular (EVA) from a command module during transearth coast. The latter feat performed by Worden during three excursions to \"Endeavour's\" SIM-bay where he retrieved film cassettes from the panoramic and mapping cameras and reported his personal observations of the general condition of equipment housed there. Apollo 15 concluded with a Pacific Ocean splashdown and subsequent recovery by the USS OKINAWA."},{"name":"edgar mitchell","body":"Mitchell was a member of Group 5, selected for astronaut training in April 1966. He served as a member of the astronaut support crew for Apollo 9 and as backup lunar module pilot for Apollo 10. On January 31, 1971, serving as lunar module pilot, Dr. Edgar Mitchell, then a U.S. Navy Captain, embarked on a journey through outer space of some 500,000 miles that resulted in becoming the sixth man to walk on the moon. That historic journey terminated safely nine days later on February 9, 1971 and was made in the company of two other men of valor Admiral Alan Shepard and Colonel Stuart Roosa. Maneuvering their lunar module, Antares, to a landing in the hilly upland Fra Mauro region of the moon, Shepard and Mitchell subsequently deployed and activated various scientific equipment and experiments and collected almost 100 pounds of lunar samples for return to Earth. Other Apollo 14 achievements included: first use of Mobile Equipment Transporter (MET); largest payload placed in lunar orbit; longest distance traversed on the lunar surface; largest payload returned from the lunar surface; longest lunar surface stay time (33 hours); longest lunar surface EVA (9 hours and 17 minutes); first use of shortened lunar orbit rendezvous techniques; first use of color TV with new vidicon tube on lunar surface; and first extensive orbital science period conducted during CSM solo operations. In completing his first space flight, Mitchell logged a total of 216 hours and 42 minutes in space. He was subsequently designated to serve as backup lunar module pilot for Apollo 16."},{"name":"eugene cernan","body":"Captain Cernan was one of fourteen astronauts selected by NASA in October 1963. He occupied the pilot seat alongside of command pilot Tom Stafford on the Gemini IX mission. During this 3-day flight which Began on June 3, 1966, the spacecraft achieved a circular orbit of 161 statute miles; the crew used three different techniques to effect rendezvous with the previously launched Augmented Target Docking Adapter; and Cernan, the second American to walk in space, logged two hours and ten minutes outside the spacecraft in extravehicular activities. The flight ended after 72 hours and 20 minutes with a perfect re-entry and recovery as Gemini IX landed within 1-1/2 miles of the prime recovery ship USS WASP and 3/8 of a mile from the predetermined target. Cernan subsequently served as backup pilot for Gemini 12 and as backup lunar module pilot for Apollo 7. On his second space flight, he was lunar module pilot of Apollo 10, May 18-26, 1969, the first comprehensive lunar-orbital qualification and verification flight test of an Apollo lunar module. He was accompanied on the 248,000 nautical sojourn to the moon by Thomas P. Stafford (spacecraft commander) and John W. Young (commander module pilot). In accomplishing all of the assigned objectives of this mission, Apollo 10 confirmed the operations performance, stability, and reliability of the command/service module and lunar module configuration during trans-lunar coast, lunar orbit insertion, and lunar module separation and descent to within 8 nautical miles of the lunar surface. The latter maneuver involved employing all but the final minutes of the technique prescribed for use in an actual lunar landing, and allowed critical evaluations of the lunar module propulsions systems and rendezvous of the landing radar devices in subsequent rendezvous and re-docking maneuvers. In addition to demonstrating that man could navigate safely and accurately in the moon's gravitational fields, Apollo 10 photographed and mapped tentative landing sites for future missions. Cernan's next assignment was backup spacecraft commander for Apollo 14. He made his third space flight as spacecraft commander of Apollo 17--the last scheduled manned mission to the moon for the United States--which commenced at 11:33 P.M. (CST), December 6, 1972, with the first manned nighttime launch, and concluded on December 19, 1972. With him on the voyage of the command module \"America\" and the lunar module \"Challenger\" were Ronald Evans (command module pilot) and Harrison H. (Jack) Schmitt (lunar module pilot). In maneuvering \"Challenger\" to a landing at Taurus-Littrow, located on the southeast edge of Mare Serenitatis, Cernan and Schmitt activated a base of operations from which they completed three highly successful excursions to the nearby craters and the Taurus mountains, making the Moon their home for over three days. This last mission to the moon established several new records for manned space flight that include: longest manned lunar landing flight (301 hours 51 minutes); longest lunar surface extravehicular activities (22 hours 6 minutes); largest lunar sample return (an estimated 115 kg (249 lbs.); and longest time in lunar orbit (147 hours 48 minutes). While Cernan and Schmitt conducted activities on the lunar surface, Evans remained in lunar orbit aboard the \"America\" completing assigned work tasks requiring geological observations, handheld photography of specific targets, and the control of cameras and other highly sophisticated scientific equipment carried in the command module SIM-bay. Evans also completed a 1-hour, 6-minute extravehicular activity on the transearth coast phase of the return flight, successfully retrieving three camera cassettes and completing a personal inspection of the equipment bay area. Apollo 17 ended with a splashdown in the Pacific Ocean approximately 0.4 miles from the target point and 4.3 miles form the prime recovery ship USS TICONDEROGA. Captain Cernan was the second American to have walked in space having spanned the circumference of the world twice in a little more than 2-1/2 hours. He was one of the two men to have flown to the moon on two occasions, and as commander of the last mission to the moon, Apollo 17, had the privilege and distinction of being the last man to have left his footprints on the surface of the moon."},{"name":"harrison schmitt","body":"Dr. Schmitt was selected as a scientist-astronaut by NASA in June 1965. He later completed a 53-week course in flight training at Williams Air Force Base, Arizona. In addition to training for future manned space flights. He was instrumental in providing Apollo flight crews with detailed instruction in lunar navigation, geology, and feature recognition. Schmitt also assisted in the integration of scientific activities into the Apollo lunar missions and participated in research activities requiring geologic, petrographic, and stratigraphic analyses of samples returned from the moon by Apollo missions. On his first journey into space, Dr. Schmitt occupied the lunar module pilot seat for Apollo 17 -- the last scheduled manned Apollo mission to the United States --which commenced at 11:33 p.m. (CST), December 6, 1972, and concluded on December 19, 1972. He was accompanied on the voyage of the command module \"America\" and the lunar module \"Challenger\" by Eugene Cernan (spacecraft commander) and Ronald Evans (command module pilot). In maneuvering \"Challenger\" to a landing at Taurus-Littrow, which is located on the southeast edge of Mare Serenitatis, Schmitt and Cernan activated a base of operations facilitating their completion of three days of exploration. This last Apollo mission to the moon for the United States broke several records set by previous flights and include: longest manned lunar landing flight (301 hours, 51 minutes); longest lunar surface extravehicular activities (22 hours, 4 minutes); largest lunar sample return (an estimated 115 Kg, 249 lbs); and longest time in lunar orbit (147 hours, 48 minutes). Apollo 17 ended with a splashdown in the Pacific Ocean approximately 0.4 mile from the target point and 4.3 miles from the prime recovery ship, USS TICONDEROGA."},{"name":"james irwin","body":"Colonel Irwin was one of the 19 astronauts selected by NASA in April 1966. He was crew commander of lunar module (LTA-8)-this vehicle finished the first series of thermal vacuum tests on June 1, 1968. He also served as a member of the astronaut support crew for Apollo 10 and as backup lunar module pilot for the Apollo 12 flight. Irwin served as lunar module pilot for Apollo, July 26 to August 7, 1971. His companions on the flight were David R. Scott, spacecraft commander and Alfred M. Worden, command module pilot. Apollo 15 was the fourth manned lunar landing mission and the first to visit and explore the moon's Hadley Rille and Apennine Mountains which are located on the southeast edge of the Mare Imbrium (Sea of Rains). The lunar module, \"Falcon\", remained on the lunar surface for 66 hours, 54 minutes-setting a new record for lunar surface stay time-and Scott and Irwin logged 18 hours and 35 minutes each in extravehicular activities conducted during three separate excursions onto the lunar surface. Using \"Rover-l\" to transport themselves and their equipment along portions of Hadley Rille and the Apinnine Mountains, Scott and Irwin performed a selenological inspection and survey of the area and collected approximately 180 pounds of lunar surface materials. They deployed an ALSEP package which involved the emplacement and activation of surface experiments, and their lunar surface activities were televised in color using a TV camera which was operated remotely by ground controllers stationed in the mission control center located at Houston, Texas. Other Apollo 15 achievements included: largest payloads ever placed in earth and lunar orbits; first scientific instrument module bay flown and operated on an Apollo spacecraft; longest distance traversed on lunar surface; first use of a lunar surface navigation device, mounted on Rover 1; first subsatellite launched in lunar orbit; and first extravehicular activity (EVA) from a command module during transearth coast. The latter feat was accomplished by Worden during three excursions to \"Endeavour's\" SIM bay where he retrieved film cassettes from the panoramic and mapping cameras and reported his personal observations of the general condition of equipment housed there. Apollo 15 concluded with a Pacific splashdown and subsequent recovery by the USS OKINAWA."},{"name":"john young","body":"In September 1962, Young was selected as an astronaut. He is the first person to fly in space six times from earth, and seven times counting his lunar liftoff. The first flight was with Gus Grissom in Gemini 3, the first manned Gemini mission, on March 23, 1965. This was a complete end-to-end test of the Gemini spacecraft, during which Gus accomplished the first manual change of orbit altitude and plane and the first lifting reentry, and Young operated the first computer on a manned spacecraft. On Gemini 10, July 18-21, 1966, Young, as Commander, and Mike Collins, as Pilot, completed a dual rendezvous with two separate Agena target vehicles. While Young flew close formation on the second Agena, Mike Collins did an extravehicular transfer to retrieve a micro meteorite detector from that Agena. On his third flight, May 18-26, 1969, Young was Command Module Pilot of Apollo 10. Tom Stafford and Gene Cernan were also on this mission which orbited the Moon, completed a lunar rendezvous, and tracked proposed lunar landing sites. His fourth space flight, Apollo 16, April 16-27, 1972, was a lunar exploration mission, with Young as Spacecraft Commander, and Ken Mattingly and Charlie Duke. Young and Duke set up scientific equipment and explored the lunar highlands at Descartes. They collected 200 pounds of rocks and drove over 16 miles in the lunar rover on three separate geology traverses. Young’s fifth flight was as Spacecraft Commander of STS-1, the first flight of the Space Shuttle, April 12-14, 1981, with Bob Crippen as Pilot. The 54-1/2 hour, 36-orbit mission verified Space Shuttle systems performance during launch, on orbit, and entry. Tests of the Orbiter Columbia included evaluation of mechanical systems including the payload bay doors, the attitude and maneuvering rocket thrusters, guidance and navigation systems, and Orbiter/crew compatibility. One hundred and thirty three of the mission’s flight test objectives were accomplished. The Orbiter Columbia was the first manned spaceship tested during ascent, on orbit, and entry without benefit of previous unmanned missions. Columbia was also the first winged reentry vehicle to return from space to a runway landing. It weighed about 98 tons as Young landed it on the dry lakebed at Edwards Air Force Base, California. Young’s sixth flight was as Spacecraft Commander of STS-9, the first Spacelab mission, November 28-December 8, 1983, with Pilot Brewster Shaw, Mission Specialists Bob Parker and Owen Garriott, and Payload Specialists Byron Lichtenberg of the USA and Ulf Merbold of West Germany. The mission successfully completed all 94 of its flight test objectives. For ten days the 6-man crew worked 12-hour shifts around-the-clock, performing more than 70 experiments in the fields of atmospheric physics, Earth observations, space plasma physics, astronomy and solar physics, materials processing and life sciences. The mission returned more scientific and technical data than all the previous Apollo and Skylab missions put together. The Spacelab was brought back for re-use, so that Columbia weighed over 110 tons as Young landed the spaceship at Edwards Air Force Base, California."},{"name":"neil armstrong","body":"As a research pilot at NASA’s Flight Research Center, Edwards, California, Armstrong was a project pilot on many pioneering high speed aircraft, including the well known, 4000-mph X-15. He flew more than 200 different models of aircraft, including jets, rockets, helicopters and gliders. Armstrong transferred to astronaut status in 1962. He was assigned as command pilot for the Gemini 8 mission. Gemini 8 was launched on March 16, 1966, and Armstrong performed the first successful docking of two vehicles in space. As spacecraft commander for Apollo 11, the first manned lunar landing mission, Armstrong gained the distinction of being the first man to land a craft on the moon and first to step on its surface. Armstrong subsequently held the position of Deputy Associate Administrator for Aeronautics, NASA Headquarters, Washington, D.C. In this position, he was responsible for the coordination and management of overall NASA research and technology work related to aeronautics."},{"name":"pete conrad","body":"In September of 1962, Mr. Conrad was selected as an astronaut by NASA. His first flight was Gemini V, which established the space endurance record and placed the United States in the lead for man-hours in space. As commander of Gemini XI, Mr. Conrad helped to set a world's altitude record. He then served as commander of Apollo XII, the second lunar landing. On Mr. Conrad's final mission, he served as commander of Skylab II, the first United States Space Station. In December 1973, after serving 20 years (11 of which were as an astronaut in the space program), Mr. Conrad retired from the U.S. Navy to accept a position as Vice President - Operations and Chief Operating Office of American Television and Communications Corporation (ATC). At ATC, he was responsible for both the operation of existing systems and the national development of new cable television systems. In 1976, he resigned from ATC to accept the position of Vice President and consultant to McDonnell Douglas Corporation. In 1978, he became Vice President of marketing and was responsible for all commercial and military sales for Douglas Aircraft Company. Mr. Conrad then became Senior Vice President-Marketing in 1980. He was appointed as Senior Vice President Marketing and Product Support in 1982 and 1984, was named Staff Vice President of International Business Development for McDonnell Douglas Corporation."}] 2 | --------------------------------------------------------------------------------